aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php74
-rw-r--r--src/Wallabag/AnnotationBundle/Entity/Annotation.php2
-rw-r--r--src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php20
-rw-r--r--src/Wallabag/ApiBundle/Controller/AnnotationRestController.php111
-rw-r--r--src/Wallabag/ApiBundle/Controller/DeveloperController.php8
-rw-r--r--src/Wallabag/ApiBundle/Controller/EntryRestController.php76
-rw-r--r--src/Wallabag/ApiBundle/Controller/TagRestController.php16
-rw-r--r--src/Wallabag/ApiBundle/Controller/WallabagRestController.php18
-rw-r--r--src/Wallabag/ApiBundle/Entity/Client.php17
-rw-r--r--src/Wallabag/ApiBundle/Resources/config/routing_rest.yml18
-rw-r--r--src/Wallabag/CoreBundle/Command/InstallCommand.php56
-rw-r--r--src/Wallabag/CoreBundle/Controller/ConfigController.php110
-rw-r--r--src/Wallabag/CoreBundle/Controller/EntryController.php49
-rw-r--r--src/Wallabag/CoreBundle/Controller/ExportController.php2
-rw-r--r--src/Wallabag/CoreBundle/Controller/RssController.php36
-rw-r--r--src/Wallabag/CoreBundle/Controller/TagController.php10
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php3
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php22
-rw-r--r--src/Wallabag/CoreBundle/Entity/Config.php30
-rw-r--r--src/Wallabag/CoreBundle/Entity/Entry.php39
-rw-r--r--src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php26
-rw-r--r--src/Wallabag/CoreBundle/Event/EntrySavedEvent.php26
-rw-r--r--src/Wallabag/CoreBundle/Event/Listener/LocaleListener.php (renamed from src/Wallabag/CoreBundle/EventListener/LocaleListener.php)2
-rw-r--r--src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php (renamed from src/Wallabag/CoreBundle/EventListener/UserLocaleListener.php)2
-rw-r--r--src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php121
-rw-r--r--src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php70
-rw-r--r--src/Wallabag/CoreBundle/Event/Subscriber/TablePrefixSubscriber.php (renamed from src/Wallabag/CoreBundle/Subscriber/TablePrefixSubscriber.php)4
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/ConfigType.php8
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php18
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/NewTagType.php11
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/SearchEntryType.php29
-rw-r--r--src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php68
-rw-r--r--src/Wallabag/CoreBundle/Helper/ContentProxy.php6
-rw-r--r--src/Wallabag/CoreBundle/Helper/DownloadImages.php233
-rw-r--r--src/Wallabag/CoreBundle/Helper/HttpClientFactory.php54
-rw-r--r--src/Wallabag/CoreBundle/Helper/Redirect.php16
-rw-r--r--src/Wallabag/CoreBundle/Repository/EntryRepository.php44
-rw-r--r--src/Wallabag/CoreBundle/Repository/TagRepository.php18
-rw-r--r--src/Wallabag/CoreBundle/Resources/config/services.yml65
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.da.yml68
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.de.yml70
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.en.yml62
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.es.yml68
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml69
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml68
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.it.yml68
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml146
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml86
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml67
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml68
-rw-r--r--src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml69
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/base.html.twig2
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig52
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig16
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig7
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/search_form.html.twig17
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig12
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_title.html.twig4
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig10
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig195
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig12
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig48
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig17
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig30
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/search_form.html.twig15
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/new_form.html.twig3
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig18
-rw-r--r--src/Wallabag/ImportBundle/Command/ImportCommand.php30
-rw-r--r--src/Wallabag/ImportBundle/Command/RedisWorkerCommand.php2
-rw-r--r--src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php9
-rw-r--r--src/Wallabag/ImportBundle/Controller/ImportController.php2
-rw-r--r--src/Wallabag/ImportBundle/Controller/PinboardController.php77
-rw-r--r--src/Wallabag/ImportBundle/Import/AbstractImport.php24
-rw-r--r--src/Wallabag/ImportBundle/Import/BrowserImport.php17
-rw-r--r--src/Wallabag/ImportBundle/Import/PinboardImport.php143
-rw-r--r--src/Wallabag/ImportBundle/Import/PocketImport.php9
-rw-r--r--src/Wallabag/ImportBundle/Resources/config/rabbit.yml15
-rw-r--r--src/Wallabag/ImportBundle/Resources/config/redis.yml28
-rw-r--r--src/Wallabag/ImportBundle/Resources/config/services.yml18
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/Chrome/index.html.twig2
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/Firefox/index.html.twig2
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/Import/_information.html.twig (renamed from src/Wallabag/ImportBundle/Resources/views/Import/_workerEnabled.html.twig)7
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig2
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/Instapaper/index.html.twig2
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/Pinboard/index.html.twig45
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig2
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/Readability/index.html.twig2
-rw-r--r--src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig2
-rw-r--r--src/Wallabag/UserBundle/Entity/User.php26
-rw-r--r--src/Wallabag/UserBundle/Repository/UserRepository.php14
-rw-r--r--src/Wallabag/UserBundle/Resources/config/services.yml2
-rw-r--r--src/Wallabag/UserBundle/Resources/views/Resetting/check_email.html.twig (renamed from src/Wallabag/UserBundle/Resources/views/Resetting/checkEmail.html.twig)2
92 files changed, 3100 insertions, 289 deletions
diff --git a/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php b/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php
index ad083e31..c13a034f 100644
--- a/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php
+++ b/src/Wallabag/AnnotationBundle/Controller/WallabagAnnotationController.php
@@ -3,9 +3,8 @@
3namespace Wallabag\AnnotationBundle\Controller; 3namespace Wallabag\AnnotationBundle\Controller;
4 4
5use FOS\RestBundle\Controller\FOSRestController; 5use FOS\RestBundle\Controller\FOSRestController;
6use Nelmio\ApiDocBundle\Annotation\ApiDoc; 6use Symfony\Component\HttpFoundation\JsonResponse;
7use Symfony\Component\HttpFoundation\Request; 7use Symfony\Component\HttpFoundation\Request;
8use Symfony\Component\HttpFoundation\Response;
9use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 8use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
10use Wallabag\AnnotationBundle\Entity\Annotation; 9use Wallabag\AnnotationBundle\Entity\Annotation;
11use Wallabag\CoreBundle\Entity\Entry; 10use Wallabag\CoreBundle\Entity\Entry;
@@ -15,42 +14,35 @@ class WallabagAnnotationController extends FOSRestController
15 /** 14 /**
16 * Retrieve annotations for an entry. 15 * Retrieve annotations for an entry.
17 * 16 *
18 * @ApiDoc( 17 * @param Entry $entry
19 * requirements={ 18 *
20 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"} 19 * @see Wallabag\ApiBundle\Controller\WallabagRestController
21 * }
22 * )
23 * 20 *
24 * @return Response 21 * @return JsonResponse
25 */ 22 */
26 public function getAnnotationsAction(Entry $entry) 23 public function getAnnotationsAction(Entry $entry)
27 { 24 {
28 $annotationRows = $this 25 $annotationRows = $this
29 ->getDoctrine() 26 ->getDoctrine()
30 ->getRepository('WallabagAnnotationBundle:Annotation') 27 ->getRepository('WallabagAnnotationBundle:Annotation')
31 ->findAnnotationsByPageId($entry->getId(), $this->getUser()->getId()); 28 ->findAnnotationsByPageId($entry->getId(), $this->getUser()->getId());
32 $total = count($annotationRows); 29 $total = count($annotationRows);
33 $annotations = ['total' => $total, 'rows' => $annotationRows]; 30 $annotations = ['total' => $total, 'rows' => $annotationRows];
34 31
35 $json = $this->get('serializer')->serialize($annotations, 'json'); 32 $json = $this->get('serializer')->serialize($annotations, 'json');
36 33
37 return $this->renderJsonResponse($json); 34 return (new JsonResponse())->setJson($json);
38 } 35 }
39 36
40 /** 37 /**
41 * Creates a new annotation. 38 * Creates a new annotation.
42 * 39 *
43 * @param Entry $entry 40 * @param Request $request
41 * @param Entry $entry
44 * 42 *
45 * @ApiDoc( 43 * @return JsonResponse
46 * requirements={
47 * {"name"="ranges", "dataType"="array", "requirement"="\w+", "description"="The range array for the annotation"},
48 * {"name"="quote", "dataType"="string", "required"=false, "description"="Optional, quote for the annotation"},
49 * {"name"="text", "dataType"="string", "required"=true, "description"=""},
50 * }
51 * )
52 * 44 *
53 * @return Response 45 * @see Wallabag\ApiBundle\Controller\WallabagRestController
54 */ 46 */
55 public function postAnnotationAction(Request $request, Entry $entry) 47 public function postAnnotationAction(Request $request, Entry $entry)
56 { 48 {
@@ -75,21 +67,20 @@ class WallabagAnnotationController extends FOSRestController
75 67
76 $json = $this->get('serializer')->serialize($annotation, 'json'); 68 $json = $this->get('serializer')->serialize($annotation, 'json');
77 69
78 return $this->renderJsonResponse($json); 70 return (new JsonResponse())->setJson($json);
79 } 71 }
80 72
81 /** 73 /**
82 * Updates an annotation. 74 * Updates an annotation.
83 * 75 *
84 * @ApiDoc( 76 * @see Wallabag\ApiBundle\Controller\WallabagRestController
85 * requirements={
86 * {"name"="annotation", "dataType"="string", "requirement"="\w+", "description"="The annotation ID"}
87 * }
88 * )
89 * 77 *
90 * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") 78 * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation")
91 * 79 *
92 * @return Response 80 * @param Annotation $annotation
81 * @param Request $request
82 *
83 * @return JsonResponse
93 */ 84 */
94 public function putAnnotationAction(Annotation $annotation, Request $request) 85 public function putAnnotationAction(Annotation $annotation, Request $request)
95 { 86 {
@@ -104,21 +95,19 @@ class WallabagAnnotationController extends FOSRestController
104 95
105 $json = $this->get('serializer')->serialize($annotation, 'json'); 96 $json = $this->get('serializer')->serialize($annotation, 'json');
106 97
107 return $this->renderJsonResponse($json); 98 return (new JsonResponse())->setJson($json);
108 } 99 }
109 100
110 /** 101 /**
111 * Removes an annotation. 102 * Removes an annotation.
112 * 103 *
113 * @ApiDoc( 104 * @see Wallabag\ApiBundle\Controller\WallabagRestController
114 * requirements={
115 * {"name"="annotation", "dataType"="string", "requirement"="\w+", "description"="The annotation ID"}
116 * }
117 * )
118 * 105 *
119 * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation") 106 * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation")
120 * 107 *
121 * @return Response 108 * @param Annotation $annotation
109 *
110 * @return JsonResponse
122 */ 111 */
123 public function deleteAnnotationAction(Annotation $annotation) 112 public function deleteAnnotationAction(Annotation $annotation)
124 { 113 {
@@ -128,19 +117,6 @@ class WallabagAnnotationController extends FOSRestController
128 117
129 $json = $this->get('serializer')->serialize($annotation, 'json'); 118 $json = $this->get('serializer')->serialize($annotation, 'json');
130 119
131 return $this->renderJsonResponse($json); 120 return (new JsonResponse())->setJson($json);
132 }
133
134 /**
135 * Send a JSON Response.
136 * We don't use the Symfony JsonRespone, because it takes an array as parameter instead of a JSON string.
137 *
138 * @param string $json
139 *
140 * @return Response
141 */
142 private function renderJsonResponse($json, $code = 200)
143 {
144 return new Response($json, $code, ['application/json']);
145 } 121 }
146} 122}
diff --git a/src/Wallabag/AnnotationBundle/Entity/Annotation.php b/src/Wallabag/AnnotationBundle/Entity/Annotation.php
index c48d8731..0838f5aa 100644
--- a/src/Wallabag/AnnotationBundle/Entity/Annotation.php
+++ b/src/Wallabag/AnnotationBundle/Entity/Annotation.php
@@ -82,7 +82,7 @@ class Annotation
82 * @Exclude 82 * @Exclude
83 * 83 *
84 * @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\Entry", inversedBy="annotations") 84 * @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\Entry", inversedBy="annotations")
85 * @ORM\JoinColumn(name="entry_id", referencedColumnName="id") 85 * @ORM\JoinColumn(name="entry_id", referencedColumnName="id", onDelete="cascade")
86 */ 86 */
87 private $entry; 87 private $entry;
88 88
diff --git a/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php b/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php
index 5f7da70e..8d3f07ee 100644
--- a/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php
+++ b/src/Wallabag/AnnotationBundle/Repository/AnnotationRepository.php
@@ -50,7 +50,8 @@ class AnnotationRepository extends EntityRepository
50 { 50 {
51 return $this->createQueryBuilder('a') 51 return $this->createQueryBuilder('a')
52 ->andWhere('a.id = :annotationId')->setParameter('annotationId', $annotationId) 52 ->andWhere('a.id = :annotationId')->setParameter('annotationId', $annotationId)
53 ->getQuery()->getSingleResult() 53 ->getQuery()
54 ->getSingleResult()
54 ; 55 ;
55 } 56 }
56 57
@@ -67,7 +68,8 @@ class AnnotationRepository extends EntityRepository
67 return $this->createQueryBuilder('a') 68 return $this->createQueryBuilder('a')
68 ->where('a.entry = :entryId')->setParameter('entryId', $entryId) 69 ->where('a.entry = :entryId')->setParameter('entryId', $entryId)
69 ->andwhere('a.user = :userId')->setParameter('userId', $userId) 70 ->andwhere('a.user = :userId')->setParameter('userId', $userId)
70 ->getQuery()->getResult() 71 ->getQuery()
72 ->getResult()
71 ; 73 ;
72 } 74 }
73 75
@@ -106,4 +108,18 @@ class AnnotationRepository extends EntityRepository
106 ->getQuery() 108 ->getQuery()
107 ->getSingleResult(); 109 ->getSingleResult();
108 } 110 }
111
112 /**
113 * Remove all annotations for a user id.
114 * Used when a user want to reset all informations.
115 *
116 * @param int $userId
117 */
118 public function removeAllByUserId($userId)
119 {
120 $this->getEntityManager()
121 ->createQuery('DELETE FROM Wallabag\AnnotationBundle\Entity\Annotation a WHERE a.user = :userId')
122 ->setParameter('userId', $userId)
123 ->execute();
124 }
109} 125}
diff --git a/src/Wallabag/ApiBundle/Controller/AnnotationRestController.php b/src/Wallabag/ApiBundle/Controller/AnnotationRestController.php
new file mode 100644
index 00000000..2dd26c07
--- /dev/null
+++ b/src/Wallabag/ApiBundle/Controller/AnnotationRestController.php
@@ -0,0 +1,111 @@
1<?php
2
3namespace Wallabag\ApiBundle\Controller;
4
5use Nelmio\ApiDocBundle\Annotation\ApiDoc;
6use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
7use Symfony\Component\HttpFoundation\Request;
8use Symfony\Component\HttpFoundation\JsonResponse;
9use Wallabag\CoreBundle\Entity\Entry;
10use Wallabag\AnnotationBundle\Entity\Annotation;
11
12class AnnotationRestController extends WallabagRestController
13{
14 /**
15 * Retrieve annotations for an entry.
16 *
17 * @ApiDoc(
18 * requirements={
19 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
20 * }
21 * )
22 *
23 * @param Entry $entry
24 *
25 * @return JsonResponse
26 */
27 public function getAnnotationsAction(Entry $entry)
28 {
29 $this->validateAuthentication();
30
31 return $this->forward('WallabagAnnotationBundle:WallabagAnnotation:getAnnotations', [
32 'entry' => $entry,
33 ]);
34 }
35
36 /**
37 * Creates a new annotation.
38 *
39 * @ApiDoc(
40 * requirements={
41 * {"name"="ranges", "dataType"="array", "requirement"="\w+", "description"="The range array for the annotation"},
42 * {"name"="quote", "dataType"="string", "required"=false, "description"="Optional, quote for the annotation"},
43 * {"name"="text", "dataType"="string", "required"=true, "description"=""},
44 * }
45 * )
46 *
47 * @param Request $request
48 * @param Entry $entry
49 *
50 * @return JsonResponse
51 */
52 public function postAnnotationAction(Request $request, Entry $entry)
53 {
54 $this->validateAuthentication();
55
56 return $this->forward('WallabagAnnotationBundle:WallabagAnnotation:postAnnotation', [
57 'request' => $request,
58 'entry' => $entry,
59 ]);
60 }
61
62 /**
63 * Updates an annotation.
64 *
65 * @ApiDoc(
66 * requirements={
67 * {"name"="annotation", "dataType"="string", "requirement"="\w+", "description"="The annotation ID"}
68 * }
69 * )
70 *
71 * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation")
72 *
73 * @param Annotation $annotation
74 * @param Request $request
75 *
76 * @return JsonResponse
77 */
78 public function putAnnotationAction(Annotation $annotation, Request $request)
79 {
80 $this->validateAuthentication();
81
82 return $this->forward('WallabagAnnotationBundle:WallabagAnnotation:putAnnotation', [
83 'annotation' => $annotation,
84 'request' => $request,
85 ]);
86 }
87
88 /**
89 * Removes an annotation.
90 *
91 * @ApiDoc(
92 * requirements={
93 * {"name"="annotation", "dataType"="string", "requirement"="\w+", "description"="The annotation ID"}
94 * }
95 * )
96 *
97 * @ParamConverter("annotation", class="WallabagAnnotationBundle:Annotation")
98 *
99 * @param Annotation $annotation
100 *
101 * @return JsonResponse
102 */
103 public function deleteAnnotationAction(Annotation $annotation)
104 {
105 $this->validateAuthentication();
106
107 return $this->forward('WallabagAnnotationBundle:WallabagAnnotation:deleteAnnotation', [
108 'annotation' => $annotation,
109 ]);
110 }
111}
diff --git a/src/Wallabag/ApiBundle/Controller/DeveloperController.php b/src/Wallabag/ApiBundle/Controller/DeveloperController.php
index 5a36a260..550c0608 100644
--- a/src/Wallabag/ApiBundle/Controller/DeveloperController.php
+++ b/src/Wallabag/ApiBundle/Controller/DeveloperController.php
@@ -19,7 +19,7 @@ class DeveloperController extends Controller
19 */ 19 */
20 public function indexAction() 20 public function indexAction()
21 { 21 {
22 $clients = $this->getDoctrine()->getRepository('WallabagApiBundle:Client')->findAll(); 22 $clients = $this->getDoctrine()->getRepository('WallabagApiBundle:Client')->findByUser($this->getUser()->getId());
23 23
24 return $this->render('@WallabagCore/themes/common/Developer/index.html.twig', [ 24 return $this->render('@WallabagCore/themes/common/Developer/index.html.twig', [
25 'clients' => $clients, 25 'clients' => $clients,
@@ -38,7 +38,7 @@ class DeveloperController extends Controller
38 public function createClientAction(Request $request) 38 public function createClientAction(Request $request)
39 { 39 {
40 $em = $this->getDoctrine()->getManager(); 40 $em = $this->getDoctrine()->getManager();
41 $client = new Client(); 41 $client = new Client($this->getUser());
42 $clientForm = $this->createForm(ClientType::class, $client); 42 $clientForm = $this->createForm(ClientType::class, $client);
43 $clientForm->handleRequest($request); 43 $clientForm->handleRequest($request);
44 44
@@ -75,6 +75,10 @@ class DeveloperController extends Controller
75 */ 75 */
76 public function deleteClientAction(Client $client) 76 public function deleteClientAction(Client $client)
77 { 77 {
78 if (null === $this->getUser() || $client->getUser()->getId() != $this->getUser()->getId()) {
79 throw $this->createAccessDeniedException('You can not access this client.');
80 }
81
78 $em = $this->getDoctrine()->getManager(); 82 $em = $this->getDoctrine()->getManager();
79 $em->remove($client); 83 $em->remove($client);
80 $em->flush(); 84 $em->flush();
diff --git a/src/Wallabag/ApiBundle/Controller/EntryRestController.php b/src/Wallabag/ApiBundle/Controller/EntryRestController.php
index 24fa7b3b..2c2ec0c1 100644
--- a/src/Wallabag/ApiBundle/Controller/EntryRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php
@@ -10,6 +10,8 @@ use Symfony\Component\HttpFoundation\JsonResponse;
10use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 10use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
11use Wallabag\CoreBundle\Entity\Entry; 11use Wallabag\CoreBundle\Entity\Entry;
12use Wallabag\CoreBundle\Entity\Tag; 12use Wallabag\CoreBundle\Entity\Tag;
13use Wallabag\CoreBundle\Event\EntrySavedEvent;
14use Wallabag\CoreBundle\Event\EntryDeletedEvent;
13 15
14class EntryRestController extends WallabagRestController 16class EntryRestController extends WallabagRestController
15{ 17{
@@ -149,6 +151,28 @@ class EntryRestController extends WallabagRestController
149 } 151 }
150 152
151 /** 153 /**
154 * Retrieve a single entry as a predefined format.
155 *
156 * @ApiDoc(
157 * requirements={
158 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
159 * }
160 * )
161 *
162 * @return Response
163 */
164 public function getEntryExportAction(Entry $entry, Request $request)
165 {
166 $this->validateAuthentication();
167 $this->validateUserAccess($entry->getUser()->getId());
168
169 return $this->get('wallabag_core.helper.entries_export')
170 ->setEntries($entry)
171 ->updateTitle('entry')
172 ->exportAs($request->attributes->get('_format'));
173 }
174
175 /**
152 * Create an entry. 176 * Create an entry.
153 * 177 *
154 * @ApiDoc( 178 * @ApiDoc(
@@ -200,9 +224,11 @@ class EntryRestController extends WallabagRestController
200 224
201 $em = $this->getDoctrine()->getManager(); 225 $em = $this->getDoctrine()->getManager();
202 $em->persist($entry); 226 $em->persist($entry);
203
204 $em->flush(); 227 $em->flush();
205 228
229 // entry saved, dispatch event about it!
230 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
231
206 $json = $this->get('serializer')->serialize($entry, 'json'); 232 $json = $this->get('serializer')->serialize($entry, 'json');
207 233
208 return (new JsonResponse())->setJson($json); 234 return (new JsonResponse())->setJson($json);
@@ -260,6 +286,51 @@ class EntryRestController extends WallabagRestController
260 } 286 }
261 287
262 /** 288 /**
289 * Reload an entry.
290 * An empty response with HTTP Status 304 will be send if we weren't able to update the content (because it hasn't changed or we got an error).
291 *
292 * @ApiDoc(
293 * requirements={
294 * {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
295 * }
296 * )
297 *
298 * @return JsonResponse
299 */
300 public function patchEntriesReloadAction(Entry $entry)
301 {
302 $this->validateAuthentication();
303 $this->validateUserAccess($entry->getUser()->getId());
304
305 try {
306 $entry = $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl());
307 } catch (\Exception $e) {
308 $this->get('logger')->error('Error while saving an entry', [
309 'exception' => $e,
310 'entry' => $entry,
311 ]);
312
313 return new JsonResponse([], 304);
314 }
315
316 // if refreshing entry failed, don't save it
317 if ($this->getParameter('wallabag_core.fetching_error_message') === $entry->getContent()) {
318 return new JsonResponse([], 304);
319 }
320
321 $em = $this->getDoctrine()->getManager();
322 $em->persist($entry);
323 $em->flush();
324
325 // entry saved, dispatch event about it!
326 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
327
328 $json = $this->get('serializer')->serialize($entry, 'json');
329
330 return (new JsonResponse())->setJson($json);
331 }
332
333 /**
263 * Delete **permanently** an entry. 334 * Delete **permanently** an entry.
264 * 335 *
265 * @ApiDoc( 336 * @ApiDoc(
@@ -279,6 +350,9 @@ class EntryRestController extends WallabagRestController
279 $em->remove($entry); 350 $em->remove($entry);
280 $em->flush(); 351 $em->flush();
281 352
353 // entry deleted, dispatch event about it!
354 $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry));
355
282 $json = $this->get('serializer')->serialize($entry, 'json'); 356 $json = $this->get('serializer')->serialize($entry, 'json');
283 357
284 return (new JsonResponse())->setJson($json); 358 return (new JsonResponse())->setJson($json);
diff --git a/src/Wallabag/ApiBundle/Controller/TagRestController.php b/src/Wallabag/ApiBundle/Controller/TagRestController.php
index 4e7ddc66..bc6d4e64 100644
--- a/src/Wallabag/ApiBundle/Controller/TagRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/TagRestController.php
@@ -132,22 +132,6 @@ class TagRestController extends WallabagRestController
132 } 132 }
133 133
134 /** 134 /**
135 * Retrieve version number.
136 *
137 * @ApiDoc()
138 *
139 * @return JsonResponse
140 */
141 public function getVersionAction()
142 {
143 $version = $this->container->getParameter('wallabag_core.version');
144
145 $json = $this->get('serializer')->serialize($version, 'json');
146
147 return (new JsonResponse())->setJson($json);
148 }
149
150 /**
151 * Remove orphan tag in case no entries are associated to it. 135 * Remove orphan tag in case no entries are associated to it.
152 * 136 *
153 * @param Tag|array $tags 137 * @param Tag|array $tags
diff --git a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php
index e927a890..b1e08ca4 100644
--- a/src/Wallabag/ApiBundle/Controller/WallabagRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/WallabagRestController.php
@@ -3,11 +3,27 @@
3namespace Wallabag\ApiBundle\Controller; 3namespace Wallabag\ApiBundle\Controller;
4 4
5use FOS\RestBundle\Controller\FOSRestController; 5use FOS\RestBundle\Controller\FOSRestController;
6use Nelmio\ApiDocBundle\Annotation\ApiDoc;
7use Symfony\Component\HttpFoundation\JsonResponse;
6use Symfony\Component\Security\Core\Exception\AccessDeniedException; 8use Symfony\Component\Security\Core\Exception\AccessDeniedException;
7use Wallabag\CoreBundle\Entity\Entry;
8 9
9class WallabagRestController extends FOSRestController 10class WallabagRestController extends FOSRestController
10{ 11{
12 /**
13 * Retrieve version number.
14 *
15 * @ApiDoc()
16 *
17 * @return JsonResponse
18 */
19 public function getVersionAction()
20 {
21 $version = $this->container->getParameter('wallabag_core.version');
22 $json = $this->get('serializer')->serialize($version, 'json');
23
24 return (new JsonResponse())->setJson($json);
25 }
26
11 protected function validateAuthentication() 27 protected function validateAuthentication()
12 { 28 {
13 if (false === $this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) { 29 if (false === $this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
diff --git a/src/Wallabag/ApiBundle/Entity/Client.php b/src/Wallabag/ApiBundle/Entity/Client.php
index f7898ac8..427a4c7f 100644
--- a/src/Wallabag/ApiBundle/Entity/Client.php
+++ b/src/Wallabag/ApiBundle/Entity/Client.php
@@ -4,6 +4,7 @@ namespace Wallabag\ApiBundle\Entity;
4 4
5use Doctrine\ORM\Mapping as ORM; 5use Doctrine\ORM\Mapping as ORM;
6use FOS\OAuthServerBundle\Entity\Client as BaseClient; 6use FOS\OAuthServerBundle\Entity\Client as BaseClient;
7use Wallabag\UserBundle\Entity\User;
7 8
8/** 9/**
9 * @ORM\Table("oauth2_clients") 10 * @ORM\Table("oauth2_clients")
@@ -35,9 +36,15 @@ class Client extends BaseClient
35 */ 36 */
36 protected $accessTokens; 37 protected $accessTokens;
37 38
38 public function __construct() 39 /**
40 * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="clients")
41 */
42 private $user;
43
44 public function __construct(User $user)
39 { 45 {
40 parent::__construct(); 46 parent::__construct();
47 $this->user = $user;
41 } 48 }
42 49
43 /** 50 /**
@@ -63,4 +70,12 @@ class Client extends BaseClient
63 70
64 return $this; 71 return $this;
65 } 72 }
73
74 /**
75 * @return User
76 */
77 public function getUser()
78 {
79 return $this->user;
80 }
66} 81}
diff --git a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml
index c1af9e02..57d37f4b 100644
--- a/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml
+++ b/src/Wallabag/ApiBundle/Resources/config/routing_rest.yml
@@ -1,9 +1,19 @@
1entries: 1entry:
2 type: rest 2 type: rest
3 resource: "WallabagApiBundle:EntryRest" 3 resource: "WallabagApiBundle:EntryRest"
4 name_prefix: api_ 4 name_prefix: api_
5 5
6tags: 6tag:
7 type: rest 7 type: rest
8 resource: "WallabagApiBundle:TagRest" 8 resource: "WallabagApiBundle:TagRest"
9 name_prefix: api_
10
11annotation:
12 type: rest
13 resource: "WallabagApiBundle:AnnotationRest"
14 name_prefix: api_
15
16misc:
17 type: rest
18 resource: "WallabagApiBundle:WallabagRest"
9 name_prefix: api_ 19 name_prefix: api_
diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php
index 2daf2dd8..f0738b91 100644
--- a/src/Wallabag/CoreBundle/Command/InstallCommand.php
+++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php
@@ -40,7 +40,7 @@ class InstallCommand extends ContainerAwareCommand
40 { 40 {
41 $this 41 $this
42 ->setName('wallabag:install') 42 ->setName('wallabag:install')
43 ->setDescription('Wallabag installer.') 43 ->setDescription('wallabag installer.')
44 ->addOption( 44 ->addOption(
45 'reset', 45 'reset',
46 null, 46 null,
@@ -55,7 +55,7 @@ class InstallCommand extends ContainerAwareCommand
55 $this->defaultInput = $input; 55 $this->defaultInput = $input;
56 $this->defaultOutput = $output; 56 $this->defaultOutput = $output;
57 57
58 $output->writeln('<info>Installing Wallabag...</info>'); 58 $output->writeln('<info>Installing wallabag...</info>');
59 $output->writeln(''); 59 $output->writeln('');
60 60
61 $this 61 $this
@@ -65,7 +65,7 @@ class InstallCommand extends ContainerAwareCommand
65 ->setupConfig() 65 ->setupConfig()
66 ; 66 ;
67 67
68 $output->writeln('<info>Wallabag has been successfully installed.</info>'); 68 $output->writeln('<info>wallabag has been successfully installed.</info>');
69 $output->writeln('<comment>Just execute `php bin/console server:run --env=prod` for using wallabag: http://localhost:8000</comment>'); 69 $output->writeln('<comment>Just execute `php bin/console server:run --env=prod` for using wallabag: http://localhost:8000</comment>');
70 } 70 }
71 71
@@ -78,7 +78,7 @@ class InstallCommand extends ContainerAwareCommand
78 78
79 // testing if database driver exists 79 // testing if database driver exists
80 $fulfilled = true; 80 $fulfilled = true;
81 $label = '<comment>PDO Driver</comment>'; 81 $label = '<comment>PDO Driver (%s)</comment>';
82 $status = '<info>OK!</info>'; 82 $status = '<info>OK!</info>';
83 $help = ''; 83 $help = '';
84 84
@@ -88,7 +88,7 @@ class InstallCommand extends ContainerAwareCommand
88 $help = 'Database driver "'.$this->getContainer()->getParameter('database_driver').'" is not installed.'; 88 $help = 'Database driver "'.$this->getContainer()->getParameter('database_driver').'" is not installed.';
89 } 89 }
90 90
91 $rows[] = [$label, $status, $help]; 91 $rows[] = [sprintf($label, $this->getContainer()->getParameter('database_driver')), $status, $help];
92 92
93 // testing if connection to the database can be etablished 93 // testing if connection to the database can be etablished
94 $label = '<comment>Database connection</comment>'; 94 $label = '<comment>Database connection</comment>';
@@ -96,7 +96,8 @@ class InstallCommand extends ContainerAwareCommand
96 $help = ''; 96 $help = '';
97 97
98 try { 98 try {
99 $doctrineManager->getConnection()->connect(); 99 $conn = $this->getContainer()->get('doctrine')->getManager()->getConnection();
100 $conn->connect();
100 } catch (\Exception $e) { 101 } catch (\Exception $e) {
101 if (false === strpos($e->getMessage(), 'Unknown database') 102 if (false === strpos($e->getMessage(), 'Unknown database')
102 && false === strpos($e->getMessage(), 'database "'.$this->getContainer()->getParameter('database_name').'" does not exist')) { 103 && false === strpos($e->getMessage(), 'database "'.$this->getContainer()->getParameter('database_name').'" does not exist')) {
@@ -108,12 +109,25 @@ class InstallCommand extends ContainerAwareCommand
108 109
109 $rows[] = [$label, $status, $help]; 110 $rows[] = [$label, $status, $help];
110 111
111 // testing if PostgreSQL > 9.1 112 // check MySQL & PostgreSQL version
112 $label = '<comment>SGBD version</comment>'; 113 $label = '<comment>Database version</comment>';
113 $status = '<info>OK!</info>'; 114 $status = '<info>OK!</info>';
114 $help = ''; 115 $help = '';
115 116
116 if ('postgresql' === $doctrineManager->getConnection()->getSchemaManager()->getDatabasePlatform()->getName()) { 117 // now check if MySQL isn't too old to handle utf8mb4
118 if ($conn->isConnected() && 'mysql' === $conn->getDatabasePlatform()->getName()) {
119 $version = $conn->query('select version()')->fetchColumn();
120 $minimalVersion = '5.5.4';
121
122 if (false === version_compare($version, $minimalVersion, '>')) {
123 $fulfilled = false;
124 $status = '<error>ERROR!</error>';
125 $help = 'Your MySQL version ('.$version.') is too old, consider upgrading ('.$minimalVersion.'+).';
126 }
127 }
128
129 // testing if PostgreSQL > 9.1
130 if ($conn->isConnected() && 'postgresql' === $conn->getDatabasePlatform()->getName()) {
117 // return version should be like "PostgreSQL 9.5.4 on x86_64-apple-darwin15.6.0, compiled by Apple LLVM version 8.0.0 (clang-800.0.38), 64-bit" 131 // return version should be like "PostgreSQL 9.5.4 on x86_64-apple-darwin15.6.0, compiled by Apple LLVM version 8.0.0 (clang-800.0.38), 64-bit"
118 $version = $doctrineManager->getConnection()->query('SELECT version();')->fetchColumn(); 132 $version = $doctrineManager->getConnection()->query('SELECT version();')->fetchColumn();
119 133
@@ -152,7 +166,7 @@ class InstallCommand extends ContainerAwareCommand
152 throw new \RuntimeException('Some system requirements are not fulfilled. Please check output messages and fix them.'); 166 throw new \RuntimeException('Some system requirements are not fulfilled. Please check output messages and fix them.');
153 } 167 }
154 168
155 $this->defaultOutput->writeln('<info>Success! Your system can run Wallabag properly.</info>'); 169 $this->defaultOutput->writeln('<info>Success! Your system can run wallabag properly.</info>');
156 170
157 $this->defaultOutput->writeln(''); 171 $this->defaultOutput->writeln('');
158 172
@@ -299,6 +313,16 @@ class InstallCommand extends ContainerAwareCommand
299 'section' => 'entry', 313 'section' => 'entry',
300 ], 314 ],
301 [ 315 [
316 'name' => 'share_unmark',
317 'value' => '1',
318 'section' => 'entry',
319 ],
320 [
321 'name' => 'unmark_url',
322 'value' => 'https://unmark.it',
323 'section' => 'entry',
324 ],
325 [
302 'name' => 'share_shaarli', 326 'name' => 'share_shaarli',
303 'value' => '1', 327 'value' => '1',
304 'section' => 'entry', 328 'section' => 'entry',
@@ -375,7 +399,7 @@ class InstallCommand extends ContainerAwareCommand
375 ], 399 ],
376 [ 400 [
377 'name' => 'wallabag_url', 401 'name' => 'wallabag_url',
378 'value' => 'http://v2.wallabag.org', 402 'value' => '',
379 'section' => 'misc', 403 'section' => 'misc',
380 ], 404 ],
381 [ 405 [
@@ -403,6 +427,16 @@ class InstallCommand extends ContainerAwareCommand
403 'value' => 'wallabag', 427 'value' => 'wallabag',
404 'section' => 'misc', 428 'section' => 'misc',
405 ], 429 ],
430 [
431 'name' => 'download_images_enabled',
432 'value' => '0',
433 'section' => 'misc',
434 ],
435 [
436 'name' => 'restricted_access',
437 'value' => '0',
438 'section' => 'entry',
439 ],
406 ]; 440 ];
407 441
408 foreach ($settings as $setting) { 442 foreach ($settings as $setting) {
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php
index 46fb9503..52a03070 100644
--- a/src/Wallabag/CoreBundle/Controller/ConfigController.php
+++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php
@@ -7,6 +7,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\JsonResponse; 7use Symfony\Component\HttpFoundation\JsonResponse;
8use Symfony\Component\HttpFoundation\RedirectResponse; 8use Symfony\Component\HttpFoundation\RedirectResponse;
9use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
10use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
10use Wallabag\CoreBundle\Entity\Config; 11use Wallabag\CoreBundle\Entity\Config;
11use Wallabag\CoreBundle\Entity\TaggingRule; 12use Wallabag\CoreBundle\Entity\TaggingRule;
12use Wallabag\CoreBundle\Form\Type\ConfigType; 13use Wallabag\CoreBundle\Form\Type\ConfigType;
@@ -150,6 +151,10 @@ class ConfigController extends Controller
150 'token' => $config->getRssToken(), 151 'token' => $config->getRssToken(),
151 ], 152 ],
152 'twofactor_auth' => $this->getParameter('twofactor_auth'), 153 'twofactor_auth' => $this->getParameter('twofactor_auth'),
154 'wallabag_url' => $this->get('craue_config')->get('wallabag_url'),
155 'enabled_users' => $this->getDoctrine()
156 ->getRepository('WallabagUserBundle:User')
157 ->getSumEnabledUsers(),
153 ]); 158 ]);
154 } 159 }
155 160
@@ -223,6 +228,78 @@ class ConfigController extends Controller
223 } 228 }
224 229
225 /** 230 /**
231 * Remove all annotations OR tags OR entries for the current user.
232 *
233 * @Route("/reset/{type}", requirements={"id" = "annotations|tags|entries"}, name="config_reset")
234 *
235 * @return RedirectResponse
236 */
237 public function resetAction($type)
238 {
239 switch ($type) {
240 case 'annotations':
241 $this->getDoctrine()
242 ->getRepository('WallabagAnnotationBundle:Annotation')
243 ->removeAllByUserId($this->getUser()->getId());
244 break;
245
246 case 'tags':
247 $this->removeAllTagsByUserId($this->getUser()->getId());
248 break;
249
250 case 'entries':
251 // SQLite doesn't care about cascading remove, so we need to manually remove associated stuf
252 // otherwise they won't be removed ...
253 if ($this->get('doctrine')->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) {
254 $this->getDoctrine()->getRepository('WallabagAnnotationBundle:Annotation')->removeAllByUserId($this->getUser()->getId());
255 }
256
257 // manually remove tags to avoid orphan tag
258 $this->removeAllTagsByUserId($this->getUser()->getId());
259
260 $this->getDoctrine()
261 ->getRepository('WallabagCoreBundle:Entry')
262 ->removeAllByUserId($this->getUser()->getId());
263 }
264
265 $this->get('session')->getFlashBag()->add(
266 'notice',
267 'flashes.config.notice.'.$type.'_reset'
268 );
269
270 return $this->redirect($this->generateUrl('config').'#set3');
271 }
272
273 /**
274 * Remove all tags for a given user and cleanup orphan tags.
275 *
276 * @param int $userId
277 */
278 private function removeAllTagsByUserId($userId)
279 {
280 $tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findAllTags($userId);
281
282 if (empty($tags)) {
283 return;
284 }
285
286 $this->getDoctrine()
287 ->getRepository('WallabagCoreBundle:Entry')
288 ->removeTags($userId, $tags);
289
290 // cleanup orphan tags
291 $em = $this->getDoctrine()->getManager();
292
293 foreach ($tags as $tag) {
294 if (count($tag->getEntries()) === 0) {
295 $em->remove($tag);
296 }
297 }
298
299 $em->flush();
300 }
301
302 /**
226 * Validate that a rule can be edited/deleted by the current user. 303 * Validate that a rule can be edited/deleted by the current user.
227 * 304 *
228 * @param TaggingRule $rule 305 * @param TaggingRule $rule
@@ -253,4 +330,37 @@ class ConfigController extends Controller
253 330
254 return $config; 331 return $config;
255 } 332 }
333
334 /**
335 * Delete account for current user.
336 *
337 * @Route("/account/delete", name="delete_account")
338 *
339 * @param Request $request
340 *
341 * @throws AccessDeniedHttpException
342 *
343 * @return \Symfony\Component\HttpFoundation\RedirectResponse
344 */
345 public function deleteAccountAction(Request $request)
346 {
347 $enabledUsers = $this->getDoctrine()
348 ->getRepository('WallabagUserBundle:User')
349 ->getSumEnabledUsers();
350
351 if ($enabledUsers <= 1) {
352 throw new AccessDeniedHttpException();
353 }
354
355 $user = $this->getUser();
356
357 // logout current user
358 $this->get('security.token_storage')->setToken(null);
359 $request->getSession()->invalidate();
360
361 $em = $this->get('fos_user.user_manager');
362 $em->deleteUser($user);
363
364 return $this->redirect($this->generateUrl('fos_user_security_login'));
365 }
256} 366}
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php
index 97bb3d12..8c13255e 100644
--- a/src/Wallabag/CoreBundle/Controller/EntryController.php
+++ b/src/Wallabag/CoreBundle/Controller/EntryController.php
@@ -13,10 +13,37 @@ use Wallabag\CoreBundle\Form\Type\EntryFilterType;
13use Wallabag\CoreBundle\Form\Type\EditEntryType; 13use Wallabag\CoreBundle\Form\Type\EditEntryType;
14use Wallabag\CoreBundle\Form\Type\NewEntryType; 14use Wallabag\CoreBundle\Form\Type\NewEntryType;
15use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; 15use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
16use Wallabag\CoreBundle\Event\EntrySavedEvent;
17use Wallabag\CoreBundle\Event\EntryDeletedEvent;
18use Wallabag\CoreBundle\Form\Type\SearchEntryType;
16 19
17class EntryController extends Controller 20class EntryController extends Controller
18{ 21{
19 /** 22 /**
23 * @param Request $request
24 * @param int $page
25 *
26 * @Route("/search/{page}", name="search", defaults={"page" = "1"})
27 *
28 * @return \Symfony\Component\HttpFoundation\Response
29 */
30 public function searchFormAction(Request $request, $page, $currentRoute)
31 {
32 $form = $this->createForm(SearchEntryType::class);
33
34 $form->handleRequest($request);
35
36 if ($form->isValid()) {
37 return $this->showEntries('search', $request, $page);
38 }
39
40 return $this->render('WallabagCoreBundle:Entry:search_form.html.twig', [
41 'form' => $form->createView(),
42 'currentRoute' => $currentRoute,
43 ]);
44 }
45
46 /**
20 * Fetch content and update entry. 47 * Fetch content and update entry.
21 * In case it fails, entry will return to avod loosing the data. 48 * In case it fails, entry will return to avod loosing the data.
22 * 49 *
@@ -81,6 +108,9 @@ class EntryController extends Controller
81 $em->persist($entry); 108 $em->persist($entry);
82 $em->flush(); 109 $em->flush();
83 110
111 // entry saved, dispatch event about it!
112 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
113
84 return $this->redirect($this->generateUrl('homepage')); 114 return $this->redirect($this->generateUrl('homepage'));
85 } 115 }
86 116
@@ -107,6 +137,9 @@ class EntryController extends Controller
107 $em = $this->getDoctrine()->getManager(); 137 $em = $this->getDoctrine()->getManager();
108 $em->persist($entry); 138 $em->persist($entry);
109 $em->flush(); 139 $em->flush();
140
141 // entry saved, dispatch event about it!
142 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
110 } 143 }
111 144
112 return $this->redirect($this->generateUrl('homepage')); 145 return $this->redirect($this->generateUrl('homepage'));
@@ -236,8 +269,14 @@ class EntryController extends Controller
236 private function showEntries($type, Request $request, $page) 269 private function showEntries($type, Request $request, $page)
237 { 270 {
238 $repository = $this->get('wallabag_core.entry_repository'); 271 $repository = $this->get('wallabag_core.entry_repository');
272 $searchTerm = (isset($request->get('search_entry')['term']) ? $request->get('search_entry')['term'] : '');
273 $currentRoute = (!is_null($request->get('currentRoute')) ? $request->get('currentRoute') : '');
239 274
240 switch ($type) { 275 switch ($type) {
276 case 'search':
277 $qb = $repository->getBuilderForSearchByUser($this->getUser()->getId(), $searchTerm, $currentRoute);
278
279 break;
241 case 'untagged': 280 case 'untagged':
242 $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId()); 281 $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId());
243 282
@@ -286,11 +325,11 @@ class EntryController extends Controller
286 } 325 }
287 326
288 return $this->render( 327 return $this->render(
289 'WallabagCoreBundle:Entry:entries.html.twig', 328 'WallabagCoreBundle:Entry:entries.html.twig', [
290 [
291 'form' => $form->createView(), 329 'form' => $form->createView(),
292 'entries' => $entries, 330 'entries' => $entries,
293 'currentPage' => $page, 331 'currentPage' => $page,
332 'searchTerm' => $searchTerm,
294 ] 333 ]
295 ); 334 );
296 } 335 }
@@ -343,6 +382,9 @@ class EntryController extends Controller
343 $em->persist($entry); 382 $em->persist($entry);
344 $em->flush(); 383 $em->flush();
345 384
385 // entry saved, dispatch event about it!
386 $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
387
346 return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()])); 388 return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()]));
347 } 389 }
348 390
@@ -431,6 +473,9 @@ class EntryController extends Controller
431 UrlGeneratorInterface::ABSOLUTE_PATH 473 UrlGeneratorInterface::ABSOLUTE_PATH
432 ); 474 );
433 475
476 // entry deleted, dispatch event about it!
477 $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry));
478
434 $em = $this->getDoctrine()->getManager(); 479 $em = $this->getDoctrine()->getManager();
435 $em->remove($entry); 480 $em->remove($entry);
436 $em->flush(); 481 $em->flush();
diff --git a/src/Wallabag/CoreBundle/Controller/ExportController.php b/src/Wallabag/CoreBundle/Controller/ExportController.php
index 79653cfe..abc3336a 100644
--- a/src/Wallabag/CoreBundle/Controller/ExportController.php
+++ b/src/Wallabag/CoreBundle/Controller/ExportController.php
@@ -48,7 +48,7 @@ class ExportController extends Controller
48 * 48 *
49 * @Route("/export/{category}.{format}", name="export_entries", requirements={ 49 * @Route("/export/{category}.{format}", name="export_entries", requirements={
50 * "format": "epub|mobi|pdf|json|xml|txt|csv", 50 * "format": "epub|mobi|pdf|json|xml|txt|csv",
51 * "category": "all|unread|starred|archive|tag_entries|untagged" 51 * "category": "all|unread|starred|archive|tag_entries|untagged|search"
52 * }) 52 * })
53 * 53 *
54 * @return \Symfony\Component\HttpFoundation\Response 54 * @return \Symfony\Component\HttpFoundation\Response
diff --git a/src/Wallabag/CoreBundle/Controller/RssController.php b/src/Wallabag/CoreBundle/Controller/RssController.php
index 38e3b5a0..2290386f 100644
--- a/src/Wallabag/CoreBundle/Controller/RssController.php
+++ b/src/Wallabag/CoreBundle/Controller/RssController.php
@@ -3,12 +3,15 @@
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Pagerfanta\Adapter\DoctrineORMAdapter; 5use Pagerfanta\Adapter\DoctrineORMAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException;
6use Pagerfanta\Pagerfanta; 7use Pagerfanta\Pagerfanta;
7use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 8use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 9use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
10use Symfony\Component\HttpFoundation\Request;
9use Symfony\Bundle\FrameworkBundle\Controller\Controller; 11use Symfony\Bundle\FrameworkBundle\Controller\Controller;
10use Wallabag\CoreBundle\Entity\Entry; 12use Wallabag\CoreBundle\Entity\Entry;
11use Wallabag\UserBundle\Entity\User; 13use Wallabag\UserBundle\Entity\User;
14use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
12 15
13class RssController extends Controller 16class RssController extends Controller
14{ 17{
@@ -20,9 +23,9 @@ class RssController extends Controller
20 * 23 *
21 * @return \Symfony\Component\HttpFoundation\Response 24 * @return \Symfony\Component\HttpFoundation\Response
22 */ 25 */
23 public function showUnreadAction(User $user) 26 public function showUnreadAction(Request $request, User $user)
24 { 27 {
25 return $this->showEntries('unread', $user); 28 return $this->showEntries('unread', $user, $request->query->get('page', 1));
26 } 29 }
27 30
28 /** 31 /**
@@ -33,9 +36,9 @@ class RssController extends Controller
33 * 36 *
34 * @return \Symfony\Component\HttpFoundation\Response 37 * @return \Symfony\Component\HttpFoundation\Response
35 */ 38 */
36 public function showArchiveAction(User $user) 39 public function showArchiveAction(Request $request, User $user)
37 { 40 {
38 return $this->showEntries('archive', $user); 41 return $this->showEntries('archive', $user, $request->query->get('page', 1));
39 } 42 }
40 43
41 /** 44 /**
@@ -46,9 +49,9 @@ class RssController extends Controller
46 * 49 *
47 * @return \Symfony\Component\HttpFoundation\Response 50 * @return \Symfony\Component\HttpFoundation\Response
48 */ 51 */
49 public function showStarredAction(User $user) 52 public function showStarredAction(Request $request, User $user)
50 { 53 {
51 return $this->showEntries('starred', $user); 54 return $this->showEntries('starred', $user, $request->query->get('page', 1));
52 } 55 }
53 56
54 /** 57 /**
@@ -57,10 +60,11 @@ class RssController extends Controller
57 * 60 *
58 * @param string $type Entries type: unread, starred or archive 61 * @param string $type Entries type: unread, starred or archive
59 * @param User $user 62 * @param User $user
63 * @param int $page
60 * 64 *
61 * @return \Symfony\Component\HttpFoundation\Response 65 * @return \Symfony\Component\HttpFoundation\Response
62 */ 66 */
63 private function showEntries($type, User $user) 67 private function showEntries($type, User $user, $page = 1)
64 { 68 {
65 $repository = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry'); 69 $repository = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
66 70
@@ -87,8 +91,26 @@ class RssController extends Controller
87 $perPage = $user->getConfig()->getRssLimit() ?: $this->getParameter('wallabag_core.rss_limit'); 91 $perPage = $user->getConfig()->getRssLimit() ?: $this->getParameter('wallabag_core.rss_limit');
88 $entries->setMaxPerPage($perPage); 92 $entries->setMaxPerPage($perPage);
89 93
94 $url = $this->generateUrl(
95 $type.'_rss',
96 [
97 'username' => $user->getUsername(),
98 'token' => $user->getConfig()->getRssToken(),
99 ],
100 UrlGeneratorInterface::ABSOLUTE_URL
101 );
102
103 try {
104 $entries->setCurrentPage((int) $page);
105 } catch (OutOfRangeCurrentPageException $e) {
106 if ($page > 1) {
107 return $this->redirect($url.'?page='.$entries->getNbPages(), 302);
108 }
109 }
110
90 return $this->render('@WallabagCore/themes/common/Entry/entries.xml.twig', [ 111 return $this->render('@WallabagCore/themes/common/Entry/entries.xml.twig', [
91 'type' => $type, 112 'type' => $type,
113 'url' => $url,
92 'entries' => $entries, 114 'entries' => $entries,
93 ]); 115 ]);
94 } 116 }
diff --git a/src/Wallabag/CoreBundle/Controller/TagController.php b/src/Wallabag/CoreBundle/Controller/TagController.php
index 707f3bbe..a3e70fd0 100644
--- a/src/Wallabag/CoreBundle/Controller/TagController.php
+++ b/src/Wallabag/CoreBundle/Controller/TagController.php
@@ -90,15 +90,15 @@ class TagController extends Controller
90 90
91 $flatTags = []; 91 $flatTags = [];
92 92
93 foreach ($tags as $key => $tag) { 93 foreach ($tags as $tag) {
94 $nbEntries = $this->getDoctrine() 94 $nbEntries = $this->getDoctrine()
95 ->getRepository('WallabagCoreBundle:Entry') 95 ->getRepository('WallabagCoreBundle:Entry')
96 ->countAllEntriesByUserIdAndTagId($this->getUser()->getId(), $tag['id']); 96 ->countAllEntriesByUserIdAndTagId($this->getUser()->getId(), $tag->getId());
97 97
98 $flatTags[] = [ 98 $flatTags[] = [
99 'id' => $tag['id'], 99 'id' => $tag->getId(),
100 'label' => $tag['label'], 100 'label' => $tag->getLabel(),
101 'slug' => $tag['slug'], 101 'slug' => $tag->getSlug(),
102 'nbEntries' => $nbEntries, 102 'nbEntries' => $nbEntries,
103 ]; 103 ];
104 } 104 }
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php
index 921c739f..45358022 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php
@@ -21,6 +21,7 @@ class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface
21 $adminConfig->setReadingSpeed(1); 21 $adminConfig->setReadingSpeed(1);
22 $adminConfig->setLanguage('en'); 22 $adminConfig->setLanguage('en');
23 $adminConfig->setPocketConsumerKey('xxxxx'); 23 $adminConfig->setPocketConsumerKey('xxxxx');
24 $adminConfig->setActionMarkAsRead(0);
24 25
25 $manager->persist($adminConfig); 26 $manager->persist($adminConfig);
26 27
@@ -32,6 +33,7 @@ class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface
32 $bobConfig->setReadingSpeed(1); 33 $bobConfig->setReadingSpeed(1);
33 $bobConfig->setLanguage('fr'); 34 $bobConfig->setLanguage('fr');
34 $bobConfig->setPocketConsumerKey(null); 35 $bobConfig->setPocketConsumerKey(null);
36 $bobConfig->setActionMarkAsRead(1);
35 37
36 $manager->persist($bobConfig); 38 $manager->persist($bobConfig);
37 39
@@ -43,6 +45,7 @@ class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface
43 $emptyConfig->setReadingSpeed(1); 45 $emptyConfig->setReadingSpeed(1);
44 $emptyConfig->setLanguage('en'); 46 $emptyConfig->setLanguage('en');
45 $emptyConfig->setPocketConsumerKey(null); 47 $emptyConfig->setPocketConsumerKey(null);
48 $emptyConfig->setActionMarkAsRead(0);
46 49
47 $manager->persist($emptyConfig); 50 $manager->persist($emptyConfig);
48 51
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
index a5e1be65..a723656e 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadSettingData.php
@@ -36,6 +36,16 @@ class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface
36 'section' => 'entry', 36 'section' => 'entry',
37 ], 37 ],
38 [ 38 [
39 'name' => 'share_unmark',
40 'value' => '1',
41 'section' => 'entry',
42 ],
43 [
44 'name' => 'unmark_url',
45 'value' => 'https://unmark.it',
46 'section' => 'entry',
47 ],
48 [
39 'name' => 'share_shaarli', 49 'name' => 'share_shaarli',
40 'value' => '1', 50 'value' => '1',
41 'section' => 'entry', 51 'section' => 'entry',
@@ -140,6 +150,16 @@ class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface
140 'value' => 'wallabag', 150 'value' => 'wallabag',
141 'section' => 'misc', 151 'section' => 'misc',
142 ], 152 ],
153 [
154 'name' => 'download_images_enabled',
155 'value' => '0',
156 'section' => 'misc',
157 ],
158 [
159 'name' => 'restricted_access',
160 'value' => '0',
161 'section' => 'entry',
162 ],
143 ]; 163 ];
144 164
145 foreach ($settings as $setting) { 165 foreach ($settings as $setting) {
@@ -158,6 +178,6 @@ class LoadSettingData extends AbstractFixture implements OrderedFixtureInterface
158 */ 178 */
159 public function getOrder() 179 public function getOrder()
160 { 180 {
161 return 50; 181 return 29;
162 } 182 }
163} 183}
diff --git a/src/Wallabag/CoreBundle/Entity/Config.php b/src/Wallabag/CoreBundle/Entity/Config.php
index 69393ac9..e04f0a7b 100644
--- a/src/Wallabag/CoreBundle/Entity/Config.php
+++ b/src/Wallabag/CoreBundle/Entity/Config.php
@@ -16,6 +16,9 @@ use Wallabag\UserBundle\Entity\User;
16 */ 16 */
17class Config 17class Config
18{ 18{
19 const REDIRECT_TO_HOMEPAGE = 0;
20 const REDIRECT_TO_CURRENT_PAGE = 1;
21
19 /** 22 /**
20 * @var int 23 * @var int
21 * 24 *
@@ -88,6 +91,13 @@ class Config
88 private $pocketConsumerKey; 91 private $pocketConsumerKey;
89 92
90 /** 93 /**
94 * @var int
95 *
96 * @ORM\Column(name="action_mark_as_read", type="integer", nullable=true)
97 */
98 private $actionMarkAsRead;
99
100 /**
91 * @ORM\OneToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="config") 101 * @ORM\OneToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="config")
92 */ 102 */
93 private $user; 103 private $user;
@@ -310,6 +320,26 @@ class Config
310 } 320 }
311 321
312 /** 322 /**
323 * @return int
324 */
325 public function getActionMarkAsRead()
326 {
327 return $this->actionMarkAsRead;
328 }
329
330 /**
331 * @param int $actionMarkAsRead
332 *
333 * @return Config
334 */
335 public function setActionMarkAsRead($actionMarkAsRead)
336 {
337 $this->actionMarkAsRead = $actionMarkAsRead;
338
339 return $this;
340 }
341
342 /**
313 * @param TaggingRule $rule 343 * @param TaggingRule $rule
314 * 344 *
315 * @return Config 345 * @return Config
diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php
index f2da3f4d..3cf9ac1a 100644
--- a/src/Wallabag/CoreBundle/Entity/Entry.php
+++ b/src/Wallabag/CoreBundle/Entity/Entry.php
@@ -19,7 +19,11 @@ use Wallabag\AnnotationBundle\Entity\Annotation;
19 * 19 *
20 * @XmlRoot("entry") 20 * @XmlRoot("entry")
21 * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\EntryRepository") 21 * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\EntryRepository")
22 * @ORM\Table(name="`entry`") 22 * @ORM\Table(
23 * name="`entry`",
24 * options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"},
25 * indexes={@ORM\Index(name="created_at", columns={"created_at"})}
26 * )
23 * @ORM\HasLifecycleCallbacks() 27 * @ORM\HasLifecycleCallbacks()
24 * @Hateoas\Relation("self", href = "expr('/api/entries/' ~ object.getId())") 28 * @Hateoas\Relation("self", href = "expr('/api/entries/' ~ object.getId())")
25 */ 29 */
@@ -177,6 +181,15 @@ class Entry
177 private $isPublic; 181 private $isPublic;
178 182
179 /** 183 /**
184 * @var string
185 *
186 * @ORM\Column(name="http_status", type="text", nullable=true)
187 *
188 * @Groups({"entries_for_user", "export_all"})
189 */
190 private $httpStatus;
191
192 /**
180 * @Exclude 193 * @Exclude
181 * 194 *
182 * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="entries") 195 * @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="entries")
@@ -190,10 +203,10 @@ class Entry
190 * @ORM\JoinTable( 203 * @ORM\JoinTable(
191 * name="entry_tag", 204 * name="entry_tag",
192 * joinColumns={ 205 * joinColumns={
193 * @ORM\JoinColumn(name="entry_id", referencedColumnName="id") 206 * @ORM\JoinColumn(name="entry_id", referencedColumnName="id", onDelete="cascade")
194 * }, 207 * },
195 * inverseJoinColumns={ 208 * inverseJoinColumns={
196 * @ORM\JoinColumn(name="tag_id", referencedColumnName="id") 209 * @ORM\JoinColumn(name="tag_id", referencedColumnName="id", onDelete="cascade")
197 * } 210 * }
198 * ) 211 * )
199 */ 212 */
@@ -665,4 +678,24 @@ class Entry
665 { 678 {
666 $this->uuid = null; 679 $this->uuid = null;
667 } 680 }
681
682 /**
683 * @return int
684 */
685 public function getHttpStatus()
686 {
687 return $this->httpStatus;
688 }
689
690 /**
691 * @param int $httpStatus
692 *
693 * @return Entry
694 */
695 public function setHttpStatus($httpStatus)
696 {
697 $this->httpStatus = $httpStatus;
698
699 return $this;
700 }
668} 701}
diff --git a/src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php b/src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php
new file mode 100644
index 00000000..e9061d04
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php
@@ -0,0 +1,26 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\CoreBundle\Entity\Entry;
7
8/**
9 * This event is fired as soon as an entry is deleted.
10 */
11class EntryDeletedEvent extends Event
12{
13 const NAME = 'entry.deleted';
14
15 protected $entry;
16
17 public function __construct(Entry $entry)
18 {
19 $this->entry = $entry;
20 }
21
22 public function getEntry()
23 {
24 return $this->entry;
25 }
26}
diff --git a/src/Wallabag/CoreBundle/Event/EntrySavedEvent.php b/src/Wallabag/CoreBundle/Event/EntrySavedEvent.php
new file mode 100644
index 00000000..5fdb5221
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/EntrySavedEvent.php
@@ -0,0 +1,26 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event;
4
5use Symfony\Component\EventDispatcher\Event;
6use Wallabag\CoreBundle\Entity\Entry;
7
8/**
9 * This event is fired as soon as an entry was saved.
10 */
11class EntrySavedEvent extends Event
12{
13 const NAME = 'entry.saved';
14
15 protected $entry;
16
17 public function __construct(Entry $entry)
18 {
19 $this->entry = $entry;
20 }
21
22 public function getEntry()
23 {
24 return $this->entry;
25 }
26}
diff --git a/src/Wallabag/CoreBundle/EventListener/LocaleListener.php b/src/Wallabag/CoreBundle/Event/Listener/LocaleListener.php
index a1c7e5ab..b435d99e 100644
--- a/src/Wallabag/CoreBundle/EventListener/LocaleListener.php
+++ b/src/Wallabag/CoreBundle/Event/Listener/LocaleListener.php
@@ -1,6 +1,6 @@
1<?php 1<?php
2 2
3namespace Wallabag\CoreBundle\EventListener; 3namespace Wallabag\CoreBundle\Event\Listener;
4 4
5use Symfony\Component\EventDispatcher\EventSubscriberInterface; 5use Symfony\Component\EventDispatcher\EventSubscriberInterface;
6use Symfony\Component\HttpKernel\Event\GetResponseEvent; 6use Symfony\Component\HttpKernel\Event\GetResponseEvent;
diff --git a/src/Wallabag/CoreBundle/EventListener/UserLocaleListener.php b/src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php
index 82d1a63a..367cdfb0 100644
--- a/src/Wallabag/CoreBundle/EventListener/UserLocaleListener.php
+++ b/src/Wallabag/CoreBundle/Event/Listener/UserLocaleListener.php
@@ -1,6 +1,6 @@
1<?php 1<?php
2 2
3namespace Wallabag\CoreBundle\EventListener; 3namespace Wallabag\CoreBundle\Event\Listener;
4 4
5use Symfony\Component\HttpFoundation\Session\Session; 5use Symfony\Component\HttpFoundation\Session\Session;
6use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; 6use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
diff --git a/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php
new file mode 100644
index 00000000..4ebe837b
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php
@@ -0,0 +1,121 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Subscriber;
4
5use Symfony\Component\EventDispatcher\EventSubscriberInterface;
6use Psr\Log\LoggerInterface;
7use Wallabag\CoreBundle\Helper\DownloadImages;
8use Wallabag\CoreBundle\Entity\Entry;
9use Wallabag\CoreBundle\Event\EntrySavedEvent;
10use Wallabag\CoreBundle\Event\EntryDeletedEvent;
11use Doctrine\ORM\EntityManager;
12
13class DownloadImagesSubscriber implements EventSubscriberInterface
14{
15 private $em;
16 private $downloadImages;
17 private $enabled;
18 private $logger;
19
20 public function __construct(EntityManager $em, DownloadImages $downloadImages, $enabled, LoggerInterface $logger)
21 {
22 $this->em = $em;
23 $this->downloadImages = $downloadImages;
24 $this->enabled = $enabled;
25 $this->logger = $logger;
26 }
27
28 public static function getSubscribedEvents()
29 {
30 return [
31 EntrySavedEvent::NAME => 'onEntrySaved',
32 EntryDeletedEvent::NAME => 'onEntryDeleted',
33 ];
34 }
35
36 /**
37 * Download images and updated the data into the entry.
38 *
39 * @param EntrySavedEvent $event
40 */
41 public function onEntrySaved(EntrySavedEvent $event)
42 {
43 if (!$this->enabled) {
44 $this->logger->debug('DownloadImagesSubscriber: disabled.');
45
46 return;
47 }
48
49 $entry = $event->getEntry();
50
51 $html = $this->downloadImages($entry);
52 if (false !== $html) {
53 $this->logger->debug('DownloadImagesSubscriber: updated html.');
54
55 $entry->setContent($html);
56 }
57
58 // update preview picture
59 $previewPicture = $this->downloadPreviewImage($entry);
60 if (false !== $previewPicture) {
61 $this->logger->debug('DownloadImagesSubscriber: update preview picture.');
62
63 $entry->setPreviewPicture($previewPicture);
64 }
65
66 $this->em->persist($entry);
67 $this->em->flush();
68 }
69
70 /**
71 * Remove images related to the entry.
72 *
73 * @param EntryDeletedEvent $event
74 */
75 public function onEntryDeleted(EntryDeletedEvent $event)
76 {
77 if (!$this->enabled) {
78 $this->logger->debug('DownloadImagesSubscriber: disabled.');
79
80 return;
81 }
82
83 $this->downloadImages->removeImages($event->getEntry()->getId());
84 }
85
86 /**
87 * Download all images from the html.
88 *
89 * @todo If we want to add async download, it should be done in that method
90 *
91 * @param Entry $entry
92 *
93 * @return string|false False in case of async
94 */
95 private function downloadImages(Entry $entry)
96 {
97 return $this->downloadImages->processHtml(
98 $entry->getId(),
99 $entry->getContent(),
100 $entry->getUrl()
101 );
102 }
103
104 /**
105 * Download the preview picture.
106 *
107 * @todo If we want to add async download, it should be done in that method
108 *
109 * @param Entry $entry
110 *
111 * @return string|false False in case of async
112 */
113 private function downloadPreviewImage(Entry $entry)
114 {
115 return $this->downloadImages->processSingleImage(
116 $entry->getId(),
117 $entry->getPreviewPicture(),
118 $entry->getUrl()
119 );
120 }
121}
diff --git a/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php
new file mode 100644
index 00000000..3b4c4cf9
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Event/Subscriber/SQLiteCascadeDeleteSubscriber.php
@@ -0,0 +1,70 @@
1<?php
2
3namespace Wallabag\CoreBundle\Event\Subscriber;
4
5use Doctrine\Common\EventSubscriber;
6use Doctrine\ORM\Event\LifecycleEventArgs;
7use Wallabag\CoreBundle\Entity\Entry;
8use Doctrine\Bundle\DoctrineBundle\Registry;
9
10/**
11 * SQLite doesn't care about cascading remove, so we need to manually remove associated stuf for an Entry.
12 * Foreign Key Support can be enabled by running `PRAGMA foreign_keys = ON;` at runtime (AT RUNTIME !).
13 * But it needs a compilation flag that not all SQLite instance has ...
14 *
15 * @see https://www.sqlite.org/foreignkeys.html#fk_enable
16 */
17class SQLiteCascadeDeleteSubscriber implements EventSubscriber
18{
19 private $doctrine;
20
21 /**
22 * @param \Doctrine\Bundle\DoctrineBundle\Registry $doctrine
23 */
24 public function __construct(Registry $doctrine)
25 {
26 $this->doctrine = $doctrine;
27 }
28
29 /**
30 * @return array
31 */
32 public function getSubscribedEvents()
33 {
34 return [
35 'preRemove',
36 ];
37 }
38
39 /**
40 * We removed everything related to the upcoming removed entry because SQLite can't handle it on it own.
41 * We do it in the preRemove, because we can't retrieve tags in the postRemove (because the entry id is gone).
42 *
43 * @param LifecycleEventArgs $args
44 */
45 public function preRemove(LifecycleEventArgs $args)
46 {
47 $entity = $args->getEntity();
48
49 if (!$this->doctrine->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver ||
50 !$entity instanceof Entry) {
51 return;
52 }
53
54 $em = $this->doctrine->getManager();
55
56 if (null !== $entity->getTags()) {
57 foreach ($entity->getTags() as $tag) {
58 $entity->removeTag($tag);
59 }
60 }
61
62 if (null !== $entity->getAnnotations()) {
63 foreach ($entity->getAnnotations() as $annotation) {
64 $em->remove($annotation);
65 }
66 }
67
68 $em->flush();
69 }
70}
diff --git a/src/Wallabag/CoreBundle/Subscriber/TablePrefixSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/TablePrefixSubscriber.php
index 0379ad6a..711c3bf8 100644
--- a/src/Wallabag/CoreBundle/Subscriber/TablePrefixSubscriber.php
+++ b/src/Wallabag/CoreBundle/Event/Subscriber/TablePrefixSubscriber.php
@@ -1,6 +1,6 @@
1<?php 1<?php
2 2
3namespace Wallabag\CoreBundle\Subscriber; 3namespace Wallabag\CoreBundle\Event\Subscriber;
4 4
5use Doctrine\Common\EventSubscriber; 5use Doctrine\Common\EventSubscriber;
6use Doctrine\ORM\Event\LoadClassMetadataEventArgs; 6use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
@@ -39,7 +39,7 @@ class TablePrefixSubscriber implements EventSubscriber
39 return; 39 return;
40 } 40 }
41 41
42 $classMetadata->setTableName($this->prefix.$classMetadata->getTableName()); 42 $classMetadata->setPrimaryTable(['name' => $this->prefix.$classMetadata->getTableName()]);
43 43
44 foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) { 44 foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
45 if ($mapping['type'] === ClassMetadataInfo::MANY_TO_MANY && isset($classMetadata->associationMappings[$fieldName]['joinTable']['name'])) { 45 if ($mapping['type'] === ClassMetadataInfo::MANY_TO_MANY && isset($classMetadata->associationMappings[$fieldName]['joinTable']['name'])) {
diff --git a/src/Wallabag/CoreBundle/Form/Type/ConfigType.php b/src/Wallabag/CoreBundle/Form/Type/ConfigType.php
index 0bac2874..7e3b9dd4 100644
--- a/src/Wallabag/CoreBundle/Form/Type/ConfigType.php
+++ b/src/Wallabag/CoreBundle/Form/Type/ConfigType.php
@@ -7,6 +7,7 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
7use Symfony\Component\Form\Extension\Core\Type\SubmitType; 7use Symfony\Component\Form\Extension\Core\Type\SubmitType;
8use Symfony\Component\Form\FormBuilderInterface; 8use Symfony\Component\Form\FormBuilderInterface;
9use Symfony\Component\OptionsResolver\OptionsResolver; 9use Symfony\Component\OptionsResolver\OptionsResolver;
10use Wallabag\CoreBundle\Entity\Config;
10 11
11class ConfigType extends AbstractType 12class ConfigType extends AbstractType
12{ 13{
@@ -48,6 +49,13 @@ class ConfigType extends AbstractType
48 'config.form_settings.reading_speed.400_word' => '2', 49 'config.form_settings.reading_speed.400_word' => '2',
49 ], 50 ],
50 ]) 51 ])
52 ->add('action_mark_as_read', ChoiceType::class, [
53 'label' => 'config.form_settings.action_mark_as_read.label',
54 'choices' => [
55 'config.form_settings.action_mark_as_read.redirect_homepage' => Config::REDIRECT_TO_HOMEPAGE,
56 'config.form_settings.action_mark_as_read.redirect_current_page' => Config::REDIRECT_TO_CURRENT_PAGE,
57 ],
58 ])
51 ->add('language', ChoiceType::class, [ 59 ->add('language', ChoiceType::class, [
52 'choices' => array_flip($this->languages), 60 'choices' => array_flip($this->languages),
53 'label' => 'config.form_settings.language_label', 61 'label' => 'config.form_settings.language_label',
diff --git a/src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php b/src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php
index a3e36fdd..ee66c728 100644
--- a/src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php
+++ b/src/Wallabag/CoreBundle/Form/Type/EntryFilterType.php
@@ -11,6 +11,7 @@ use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\CheckboxFilterType;
11use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\ChoiceFilterType; 11use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\ChoiceFilterType;
12use Symfony\Component\Form\AbstractType; 12use Symfony\Component\Form\AbstractType;
13use Symfony\Component\Form\FormBuilderInterface; 13use Symfony\Component\Form\FormBuilderInterface;
14use Symfony\Component\HttpFoundation\Response;
14use Symfony\Component\OptionsResolver\OptionsResolver; 15use Symfony\Component\OptionsResolver\OptionsResolver;
15use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; 16use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
16 17
@@ -89,12 +90,27 @@ class EntryFilterType extends AbstractType
89 if (strlen($value) <= 2 || empty($value)) { 90 if (strlen($value) <= 2 || empty($value)) {
90 return; 91 return;
91 } 92 }
92 $expression = $filterQuery->getExpr()->like($field, $filterQuery->getExpr()->literal('%'.$value.'%')); 93 $expression = $filterQuery->getExpr()->like($field, $filterQuery->getExpr()->lower($filterQuery->getExpr()->literal('%'.$value.'%')));
93 94
94 return $filterQuery->createCondition($expression); 95 return $filterQuery->createCondition($expression);
95 }, 96 },
96 'label' => 'entry.filters.domain_label', 97 'label' => 'entry.filters.domain_label',
97 ]) 98 ])
99 ->add('httpStatus', TextFilterType::class, [
100 'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
101 $value = $values['value'];
102 if (false === array_key_exists($value, Response::$statusTexts)) {
103 return;
104 }
105
106 $paramName = sprintf('%s', str_replace('.', '_', $field));
107 $expression = $filterQuery->getExpr()->eq($field, ':'.$paramName);
108 $parameters = array($paramName => $value);
109
110 return $filterQuery->createCondition($expression, $parameters);
111 },
112 'label' => 'entry.filters.http_status_label',
113 ])
98 ->add('isArchived', CheckboxFilterType::class, [ 114 ->add('isArchived', CheckboxFilterType::class, [
99 'label' => 'entry.filters.archived_label', 115 'label' => 'entry.filters.archived_label',
100 ]) 116 ])
diff --git a/src/Wallabag/CoreBundle/Form/Type/NewTagType.php b/src/Wallabag/CoreBundle/Form/Type/NewTagType.php
index 3db4105f..e830ade4 100644
--- a/src/Wallabag/CoreBundle/Form/Type/NewTagType.php
+++ b/src/Wallabag/CoreBundle/Form/Type/NewTagType.php
@@ -3,6 +3,7 @@
3namespace Wallabag\CoreBundle\Form\Type; 3namespace Wallabag\CoreBundle\Form\Type;
4 4
5use Symfony\Component\Form\AbstractType; 5use Symfony\Component\Form\AbstractType;
6use Symfony\Component\Form\Extension\Core\Type\SubmitType;
6use Symfony\Component\Form\Extension\Core\Type\TextType; 7use Symfony\Component\Form\Extension\Core\Type\TextType;
7use Symfony\Component\Form\FormBuilderInterface; 8use Symfony\Component\Form\FormBuilderInterface;
8use Symfony\Component\OptionsResolver\OptionsResolver; 9use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -12,7 +13,15 @@ class NewTagType extends AbstractType
12 public function buildForm(FormBuilderInterface $builder, array $options) 13 public function buildForm(FormBuilderInterface $builder, array $options)
13 { 14 {
14 $builder 15 $builder
15 ->add('label', TextType::class, ['required' => true]) 16 ->add('label', TextType::class, [
17 'required' => true,
18 'attr' => [
19 'placeholder' => 'tag.new.placeholder',
20 ],
21 ])
22 ->add('add', SubmitType::class, [
23 'label' => 'tag.new.add',
24 ])
16 ; 25 ;
17 } 26 }
18 27
diff --git a/src/Wallabag/CoreBundle/Form/Type/SearchEntryType.php b/src/Wallabag/CoreBundle/Form/Type/SearchEntryType.php
new file mode 100644
index 00000000..b56cae8e
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Form/Type/SearchEntryType.php
@@ -0,0 +1,29 @@
1<?php
2
3namespace Wallabag\CoreBundle\Form\Type;
4
5use Symfony\Component\Form\AbstractType;
6use Symfony\Component\Form\Extension\Core\Type\TextType;
7use Symfony\Component\Form\FormBuilderInterface;
8use Symfony\Component\OptionsResolver\OptionsResolver;
9
10class SearchEntryType extends AbstractType
11{
12 public function buildForm(FormBuilderInterface $builder, array $options)
13 {
14 $builder
15 ->setMethod('GET')
16 ->add('term', TextType::class, [
17 'required' => true,
18 'label' => 'entry.new.form_search.term_label',
19 ])
20 ;
21 }
22
23 public function configureOptions(OptionsResolver $resolver)
24 {
25 $resolver->setDefaults([
26 'csrf_protection' => false,
27 ]);
28 }
29}
diff --git a/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php
new file mode 100644
index 00000000..6d4129e8
--- /dev/null
+++ b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php
@@ -0,0 +1,68 @@
1<?php
2
3namespace Wallabag\CoreBundle\GuzzleSiteAuthenticator;
4
5use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfig;
6use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfigBuilder;
7use Graby\SiteConfig\ConfigBuilder;
8use OutOfRangeException;
9
10class GrabySiteConfigBuilder implements SiteConfigBuilder
11{
12 /**
13 * @var \Graby\SiteConfig\ConfigBuilder
14 */
15 private $grabyConfigBuilder;
16 /**
17 * @var array
18 */
19 private $credentials;
20
21 /**
22 * GrabySiteConfigBuilder constructor.
23 *
24 * @param \Graby\SiteConfig\ConfigBuilder $grabyConfigBuilder
25 * @param array $credentials
26 */
27 public function __construct(ConfigBuilder $grabyConfigBuilder, array $credentials = [])
28 {
29 $this->grabyConfigBuilder = $grabyConfigBuilder;
30 $this->credentials = $credentials;
31 }
32
33 /**
34 * Builds the SiteConfig for a host.
35 *
36 * @param string $host The "www." prefix is ignored
37 *
38 * @return SiteConfig
39 *
40 * @throws OutOfRangeException If there is no config for $host
41 */
42 public function buildForHost($host)
43 {
44 // required by credentials below
45 $host = strtolower($host);
46 if (substr($host, 0, 4) == 'www.') {
47 $host = substr($host, 4);
48 }
49
50 $config = $this->grabyConfigBuilder->buildForHost($host);
51 $parameters = [
52 'host' => $host,
53 'requiresLogin' => $config->requires_login ?: false,
54 'loginUri' => $config->login_uri ?: null,
55 'usernameField' => $config->login_username_field ?: null,
56 'passwordField' => $config->login_password_field ?: null,
57 'extraFields' => is_array($config->login_extra_fields) ? $config->login_extra_fields : [],
58 'notLoggedInXpath' => $config->not_logged_in_xpath ?: null,
59 ];
60
61 if (isset($this->credentials[$host])) {
62 $parameters['username'] = $this->credentials[$host]['username'];
63 $parameters['password'] = $this->credentials[$host]['password'];
64 }
65
66 return new SiteConfig($parameters);
67 }
68}
diff --git a/src/Wallabag/CoreBundle/Helper/ContentProxy.php b/src/Wallabag/CoreBundle/Helper/ContentProxy.php
index bbd5db5d..fd059325 100644
--- a/src/Wallabag/CoreBundle/Helper/ContentProxy.php
+++ b/src/Wallabag/CoreBundle/Helper/ContentProxy.php
@@ -3,7 +3,7 @@
3namespace Wallabag\CoreBundle\Helper; 3namespace Wallabag\CoreBundle\Helper;
4 4
5use Graby\Graby; 5use Graby\Graby;
6use Psr\Log\LoggerInterface as Logger; 6use Psr\Log\LoggerInterface;
7use Wallabag\CoreBundle\Entity\Entry; 7use Wallabag\CoreBundle\Entity\Entry;
8use Wallabag\CoreBundle\Entity\Tag; 8use Wallabag\CoreBundle\Entity\Tag;
9use Wallabag\CoreBundle\Tools\Utils; 9use Wallabag\CoreBundle\Tools\Utils;
@@ -22,7 +22,7 @@ class ContentProxy
22 protected $tagRepository; 22 protected $tagRepository;
23 protected $mimeGuesser; 23 protected $mimeGuesser;
24 24
25 public function __construct(Graby $graby, RuleBasedTagger $tagger, TagRepository $tagRepository, Logger $logger) 25 public function __construct(Graby $graby, RuleBasedTagger $tagger, TagRepository $tagRepository, LoggerInterface $logger)
26 { 26 {
27 $this->graby = $graby; 27 $this->graby = $graby;
28 $this->tagger = $tagger; 28 $this->tagger = $tagger;
@@ -69,6 +69,8 @@ class ContentProxy
69 $entry->setUrl($content['url'] ?: $url); 69 $entry->setUrl($content['url'] ?: $url);
70 $entry->setTitle($title); 70 $entry->setTitle($title);
71 $entry->setContent($html); 71 $entry->setContent($html);
72 $entry->setHttpStatus(isset($content['status']) ? $content['status'] : '');
73
72 $entry->setLanguage($content['language']); 74 $entry->setLanguage($content['language']);
73 $entry->setMimetype($content['content_type']); 75 $entry->setMimetype($content['content_type']);
74 $entry->setReadingTime(Utils::getReadingTime($html)); 76 $entry->setReadingTime(Utils::getReadingTime($html));
diff --git a/src/Wallabag/CoreBundle/Helper/DownloadImages.php b/src/Wallabag/CoreBundle/Helper/DownloadImages.php
new file mode 100644
index 00000000..264bc6a3
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Helper/DownloadImages.php
@@ -0,0 +1,233 @@
1<?php
2
3namespace Wallabag\CoreBundle\Helper;
4
5use Psr\Log\LoggerInterface;
6use Symfony\Component\DomCrawler\Crawler;
7use GuzzleHttp\Client;
8use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeExtensionGuesser;
9use Symfony\Component\Finder\Finder;
10
11class DownloadImages
12{
13 const REGENERATE_PICTURES_QUALITY = 80;
14
15 private $client;
16 private $baseFolder;
17 private $logger;
18 private $mimeGuesser;
19 private $wallabagUrl;
20
21 public function __construct(Client $client, $baseFolder, $wallabagUrl, LoggerInterface $logger)
22 {
23 $this->client = $client;
24 $this->baseFolder = $baseFolder;
25 $this->wallabagUrl = rtrim($wallabagUrl, '/');
26 $this->logger = $logger;
27 $this->mimeGuesser = new MimeTypeExtensionGuesser();
28
29 $this->setFolder();
30 }
31
32 /**
33 * Setup base folder where all images are going to be saved.
34 */
35 private function setFolder()
36 {
37 // if folder doesn't exist, attempt to create one and store the folder name in property $folder
38 if (!file_exists($this->baseFolder)) {
39 mkdir($this->baseFolder, 0777, true);
40 }
41 }
42
43 /**
44 * Process the html and extract image from it, save them to local and return the updated html.
45 *
46 * @param int $entryId ID of the entry
47 * @param string $html
48 * @param string $url Used as a base path for relative image and folder
49 *
50 * @return string
51 */
52 public function processHtml($entryId, $html, $url)
53 {
54 $crawler = new Crawler($html);
55 $result = $crawler
56 ->filterXpath('//img')
57 ->extract(array('src'));
58
59 $relativePath = $this->getRelativePath($entryId);
60
61 // download and save the image to the folder
62 foreach ($result as $image) {
63 $imagePath = $this->processSingleImage($entryId, $image, $url, $relativePath);
64
65 if (false === $imagePath) {
66 continue;
67 }
68
69 $html = str_replace($image, $imagePath, $html);
70 }
71
72 return $html;
73 }
74
75 /**
76 * Process a single image:
77 * - retrieve it
78 * - re-saved it (for security reason)
79 * - return the new local path.
80 *
81 * @param int $entryId ID of the entry
82 * @param string $imagePath Path to the image to retrieve
83 * @param string $url Url from where the image were found
84 * @param string $relativePath Relative local path to saved the image
85 *
86 * @return string Relative url to access the image from the web
87 */
88 public function processSingleImage($entryId, $imagePath, $url, $relativePath = null)
89 {
90 if (null === $relativePath) {
91 $relativePath = $this->getRelativePath($entryId);
92 }
93
94 $this->logger->debug('DownloadImages: working on image: '.$imagePath);
95
96 $folderPath = $this->baseFolder.'/'.$relativePath;
97
98 // build image path
99 $absolutePath = $this->getAbsoluteLink($url, $imagePath);
100 if (false === $absolutePath) {
101 $this->logger->error('DownloadImages: Can not determine the absolute path for that image, skipping.');
102
103 return false;
104 }
105
106 try {
107 $res = $this->client->get($absolutePath);
108 } catch (\Exception $e) {
109 $this->logger->error('DownloadImages: Can not retrieve image, skipping.', ['exception' => $e]);
110
111 return false;
112 }
113
114 $ext = $this->mimeGuesser->guess($res->getHeader('content-type'));
115 $this->logger->debug('DownloadImages: Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]);
116 if (!in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true)) {
117 $this->logger->error('DownloadImages: Processed image with not allowed extension. Skipping '.$imagePath);
118
119 return false;
120 }
121 $hashImage = hash('crc32', $absolutePath);
122 $localPath = $folderPath.'/'.$hashImage.'.'.$ext;
123
124 try {
125 $im = imagecreatefromstring($res->getBody());
126 } catch (\Exception $e) {
127 $im = false;
128 }
129
130 if (false === $im) {
131 $this->logger->error('DownloadImages: Error while regenerating image', ['path' => $localPath]);
132
133 return false;
134 }
135
136 switch ($ext) {
137 case 'gif':
138 imagegif($im, $localPath);
139 $this->logger->debug('DownloadImages: Re-creating gif');
140 break;
141 case 'jpeg':
142 case 'jpg':
143 imagejpeg($im, $localPath, self::REGENERATE_PICTURES_QUALITY);
144 $this->logger->debug('DownloadImages: Re-creating jpg');
145 break;
146 case 'png':
147 imagepng($im, $localPath, ceil(self::REGENERATE_PICTURES_QUALITY / 100 * 9));
148 $this->logger->debug('DownloadImages: Re-creating png');
149 }
150
151 imagedestroy($im);
152
153 return $this->wallabagUrl.'/assets/images/'.$relativePath.'/'.$hashImage.'.'.$ext;
154 }
155
156 /**
157 * Remove all images for the given entry id.
158 *
159 * @param int $entryId ID of the entry
160 */
161 public function removeImages($entryId)
162 {
163 $relativePath = $this->getRelativePath($entryId);
164 $folderPath = $this->baseFolder.'/'.$relativePath;
165
166 $finder = new Finder();
167 $finder
168 ->files()
169 ->ignoreDotFiles(true)
170 ->in($folderPath);
171
172 foreach ($finder as $file) {
173 @unlink($file->getRealPath());
174 }
175
176 @rmdir($folderPath);
177 }
178
179 /**
180 * Generate the folder where we are going to save images based on the entry url.
181 *
182 * @param int $entryId ID of the entry
183 *
184 * @return string
185 */
186 private function getRelativePath($entryId)
187 {
188 $hashId = hash('crc32', $entryId);
189 $relativePath = $hashId[0].'/'.$hashId[1].'/'.$hashId;
190 $folderPath = $this->baseFolder.'/'.$relativePath;
191
192 if (!file_exists($folderPath)) {
193 mkdir($folderPath, 0777, true);
194 }
195
196 $this->logger->debug('DownloadImages: Folder used for that Entry id', ['folder' => $folderPath, 'entryId' => $entryId]);
197
198 return $relativePath;
199 }
200
201 /**
202 * Make an $url absolute based on the $base.
203 *
204 * @see Graby->makeAbsoluteStr
205 *
206 * @param string $base Base url
207 * @param string $url Url to make it absolute
208 *
209 * @return false|string
210 */
211 private function getAbsoluteLink($base, $url)
212 {
213 if (preg_match('!^https?://!i', $url)) {
214 // already absolute
215 return $url;
216 }
217
218 $base = new \SimplePie_IRI($base);
219
220 // remove '//' in URL path (causes URLs not to resolve properly)
221 if (isset($base->ipath)) {
222 $base->ipath = preg_replace('!//+!', '/', $base->ipath);
223 }
224
225 if ($absolute = \SimplePie_IRI::absolutize($base, $url)) {
226 return $absolute->get_uri();
227 }
228
229 $this->logger->error('DownloadImages: Can not make an absolute link', ['base' => $base, 'url' => $url]);
230
231 return false;
232 }
233}
diff --git a/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php b/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php
new file mode 100644
index 00000000..8891887b
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php
@@ -0,0 +1,54 @@
1<?php
2
3namespace Wallabag\CoreBundle\Helper;
4
5use Graby\Ring\Client\SafeCurlHandler;
6use GuzzleHttp\Client;
7use GuzzleHttp\Cookie\CookieJar;
8use GuzzleHttp\Event\SubscriberInterface;
9
10/**
11 * Builds and configures the Guzzle HTTP client.
12 */
13class HttpClientFactory
14{
15 /** @var \GuzzleHttp\Event\SubscriberInterface */
16 private $authenticatorSubscriber;
17
18 /** @var \GuzzleHttp\Cookie\CookieJar */
19 private $cookieJar;
20
21 private $restrictedAccess;
22
23 /**
24 * HttpClientFactory constructor.
25 *
26 * @param \GuzzleHttp\Event\SubscriberInterface $authenticatorSubscriber
27 * @param \GuzzleHttp\Cookie\CookieJar $cookieJar
28 * @param string $restrictedAccess this param is a kind of boolean. Values: 0 or 1
29 */
30 public function __construct(SubscriberInterface $authenticatorSubscriber, CookieJar $cookieJar, $restrictedAccess)
31 {
32 $this->authenticatorSubscriber = $authenticatorSubscriber;
33 $this->cookieJar = $cookieJar;
34 $this->restrictedAccess = $restrictedAccess;
35 }
36
37 /**
38 * @return \GuzzleHttp\Client|null
39 */
40 public function buildHttpClient()
41 {
42 if (0 === (int) $this->restrictedAccess) {
43 return null;
44 }
45
46 // we clear the cookie to avoid websites who use cookies for analytics
47 $this->cookieJar->clear();
48 // need to set the (shared) cookie jar
49 $client = new Client(['handler' => new SafeCurlHandler(), 'defaults' => ['cookies' => $this->cookieJar]]);
50 $client->getEmitter()->attach($this->authenticatorSubscriber);
51
52 return $client;
53 }
54}
diff --git a/src/Wallabag/CoreBundle/Helper/Redirect.php b/src/Wallabag/CoreBundle/Helper/Redirect.php
index c14c79d1..f78b7fe0 100644
--- a/src/Wallabag/CoreBundle/Helper/Redirect.php
+++ b/src/Wallabag/CoreBundle/Helper/Redirect.php
@@ -3,6 +3,8 @@
3namespace Wallabag\CoreBundle\Helper; 3namespace Wallabag\CoreBundle\Helper;
4 4
5use Symfony\Component\Routing\Router; 5use Symfony\Component\Routing\Router;
6use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
7use Wallabag\CoreBundle\Entity\Config;
6 8
7/** 9/**
8 * Manage redirections to avoid redirecting to empty routes. 10 * Manage redirections to avoid redirecting to empty routes.
@@ -10,10 +12,12 @@ use Symfony\Component\Routing\Router;
10class Redirect 12class Redirect
11{ 13{
12 private $router; 14 private $router;
15 private $tokenStorage;
13 16
14 public function __construct(Router $router) 17 public function __construct(Router $router, TokenStorageInterface $tokenStorage)
15 { 18 {
16 $this->router = $router; 19 $this->router = $router;
20 $this->tokenStorage = $tokenStorage;
17 } 21 }
18 22
19 /** 23 /**
@@ -24,6 +28,16 @@ class Redirect
24 */ 28 */
25 public function to($url, $fallback = '') 29 public function to($url, $fallback = '')
26 { 30 {
31 $user = $this->tokenStorage->getToken() ? $this->tokenStorage->getToken()->getUser() : null;
32
33 if (null === $user || !is_object($user)) {
34 return $url;
35 }
36
37 if (Config::REDIRECT_TO_HOMEPAGE === $user->getConfig()->getActionMarkAsRead()) {
38 return $this->router->generate('homepage');
39 }
40
27 if (null !== $url) { 41 if (null !== $url) {
28 return $url; 42 return $url;
29 } 43 }
diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
index 4f03ae0f..47e24d6b 100644
--- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php
@@ -86,6 +86,36 @@ class EntryRepository extends EntityRepository
86 } 86 }
87 87
88 /** 88 /**
89 * Retrieves entries filtered with a search term for a user.
90 *
91 * @param int $userId
92 * @param string $term
93 * @param strint $currentRoute
94 *
95 * @return QueryBuilder
96 */
97 public function getBuilderForSearchByUser($userId, $term, $currentRoute)
98 {
99 $qb = $this
100 ->getBuilderByUser($userId);
101
102 if ('starred' === $currentRoute) {
103 $qb->andWhere('e.isStarred = true');
104 } elseif ('unread' === $currentRoute) {
105 $qb->andWhere('e.isArchived = false');
106 } elseif ('archive' === $currentRoute) {
107 $qb->andWhere('e.isArchived = true');
108 }
109
110 $qb
111 ->andWhere('e.content LIKE :term OR e.title LIKE :term')->setParameter('term', '%'.$term.'%')
112 ->leftJoin('e.tags', 't')
113 ->groupBy('e.id');
114
115 return $qb;
116 }
117
118 /**
89 * Retrieves untagged entries for a user. 119 * Retrieves untagged entries for a user.
90 * 120 *
91 * @param int $userId 121 * @param int $userId
@@ -329,4 +359,18 @@ class EntryRepository extends EntityRepository
329 359
330 return $qb->getQuery()->getSingleScalarResult(); 360 return $qb->getQuery()->getSingleScalarResult();
331 } 361 }
362
363 /**
364 * Remove all entries for a user id.
365 * Used when a user want to reset all informations.
366 *
367 * @param int $userId
368 */
369 public function removeAllByUserId($userId)
370 {
371 $this->getEntityManager()
372 ->createQuery('DELETE FROM Wallabag\CoreBundle\Entity\Entry e WHERE e.user = :userId')
373 ->setParameter('userId', $userId)
374 ->execute();
375 }
332} 376}
diff --git a/src/Wallabag/CoreBundle/Repository/TagRepository.php b/src/Wallabag/CoreBundle/Repository/TagRepository.php
index e76878d4..81445989 100644
--- a/src/Wallabag/CoreBundle/Repository/TagRepository.php
+++ b/src/Wallabag/CoreBundle/Repository/TagRepository.php
@@ -34,6 +34,9 @@ class TagRepository extends EntityRepository
34 34
35 /** 35 /**
36 * Find all tags per user. 36 * Find all tags per user.
37 * Instead of just left joined on the Entry table, we select only id and group by id to avoid tag multiplication in results.
38 * Once we have all tags id, we can safely request them one by one.
39 * This'll still be fastest than the previous query.
37 * 40 *
38 * @param int $userId 41 * @param int $userId
39 * 42 *
@@ -41,15 +44,20 @@ class TagRepository extends EntityRepository
41 */ 44 */
42 public function findAllTags($userId) 45 public function findAllTags($userId)
43 { 46 {
44 return $this->createQueryBuilder('t') 47 $ids = $this->createQueryBuilder('t')
45 ->select('t.slug', 't.label', 't.id') 48 ->select('t.id')
46 ->leftJoin('t.entries', 'e') 49 ->leftJoin('t.entries', 'e')
47 ->where('e.user = :userId')->setParameter('userId', $userId) 50 ->where('e.user = :userId')->setParameter('userId', $userId)
48 ->groupBy('t.slug') 51 ->groupBy('t.id')
49 ->addGroupBy('t.label')
50 ->addGroupBy('t.id')
51 ->getQuery() 52 ->getQuery()
52 ->getArrayResult(); 53 ->getArrayResult();
54
55 $tags = [];
56 foreach ($ids as $id) {
57 $tags[] = $this->find($id);
58 }
59
60 return $tags;
53 } 61 }
54 62
55 /** 63 /**
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml
index ed66d2be..bcf0c9ca 100644
--- a/src/Wallabag/CoreBundle/Resources/config/services.yml
+++ b/src/Wallabag/CoreBundle/Resources/config/services.yml
@@ -30,7 +30,7 @@ services:
30 - "@doctrine" 30 - "@doctrine"
31 31
32 wallabag_core.subscriber.table_prefix: 32 wallabag_core.subscriber.table_prefix:
33 class: Wallabag\CoreBundle\Subscriber\TablePrefixSubscriber 33 class: Wallabag\CoreBundle\Event\Subscriber\TablePrefixSubscriber
34 arguments: 34 arguments:
35 - "%database_table_prefix%" 35 - "%database_table_prefix%"
36 tags: 36 tags:
@@ -41,11 +41,44 @@ services:
41 arguments: 41 arguments:
42 - 42 -
43 error_message: '%wallabag_core.fetching_error_message%' 43 error_message: '%wallabag_core.fetching_error_message%'
44 - "@wallabag_core.guzzle.http_client"
45 - "@wallabag_core.graby.config_builder"
44 calls: 46 calls:
45 - [ setLogger, [ "@logger" ] ] 47 - [ setLogger, [ "@logger" ] ]
46 tags: 48 tags:
47 - { name: monolog.logger, channel: graby } 49 - { name: monolog.logger, channel: graby }
48 50
51 wallabag_core.graby.config_builder:
52 class: Graby\SiteConfig\ConfigBuilder
53 arguments:
54 - {}
55 - "@logger"
56
57 wallabag_core.guzzle.http_client:
58 class: GuzzleHttp\ClientInterface
59 factory: ["@wallabag_core.guzzle.http_client_factory", buildHttpClient]
60
61 wallabag_core.guzzle_authenticator.config_builder:
62 class: Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder
63 arguments:
64 - "@wallabag_core.graby.config_builder"
65 - "%sites_credentials%"
66
67 # service alias override
68 bd_guzzle_site_authenticator.site_config_builder:
69 alias: wallabag_core.guzzle_authenticator.config_builder
70
71 wallabag_core.guzzle.http_client_factory:
72 class: Wallabag\CoreBundle\Helper\HttpClientFactory
73 arguments:
74 - "@bd_guzzle_site_authenticator.authenticator_subscriber"
75 - "@wallabag_core.guzzle.cookie_jar"
76 - '@=service(''craue_config'').get(''restricted_access'')'
77
78 wallabag_core.guzzle.cookie_jar:
79 class: GuzzleHttp\Cookie\FileCookieJar
80 arguments: ["%kernel.cache_dir%/cookiejar.json"]
81
49 wallabag_core.content_proxy: 82 wallabag_core.content_proxy:
50 class: Wallabag\CoreBundle\Helper\ContentProxy 83 class: Wallabag\CoreBundle\Helper\ContentProxy
51 arguments: 84 arguments:
@@ -94,6 +127,7 @@ services:
94 class: Wallabag\CoreBundle\Helper\Redirect 127 class: Wallabag\CoreBundle\Helper\Redirect
95 arguments: 128 arguments:
96 - "@router" 129 - "@router"
130 - "@security.token_storage"
97 131
98 wallabag_core.helper.prepare_pager_for_entries: 132 wallabag_core.helper.prepare_pager_for_entries:
99 class: Wallabag\CoreBundle\Helper\PreparePagerForEntries 133 class: Wallabag\CoreBundle\Helper\PreparePagerForEntries
@@ -109,9 +143,38 @@ services:
109 host: '%redis_host%' 143 host: '%redis_host%'
110 port: '%redis_port%' 144 port: '%redis_port%'
111 path: '%redis_path%' 145 path: '%redis_path%'
146 password: '%redis_password%'
112 147
113 wallabag_core.exception_controller: 148 wallabag_core.exception_controller:
114 class: Wallabag\CoreBundle\Controller\ExceptionController 149 class: Wallabag\CoreBundle\Controller\ExceptionController
115 arguments: 150 arguments:
116 - '@twig' 151 - '@twig'
117 - '%kernel.debug%' 152 - '%kernel.debug%'
153
154 wallabag_core.subscriber.sqlite_cascade_delete:
155 class: Wallabag\CoreBundle\Event\Subscriber\SQLiteCascadeDeleteSubscriber
156 arguments:
157 - "@doctrine"
158 tags:
159 - { name: doctrine.event_subscriber }
160
161 wallabag_core.subscriber.download_images:
162 class: Wallabag\CoreBundle\Event\Subscriber\DownloadImagesSubscriber
163 arguments:
164 - "@doctrine.orm.default_entity_manager"
165 - "@wallabag_core.entry.download_images"
166 - '@=service(''craue_config'').get(''download_images_enabled'')'
167 - "@logger"
168 tags:
169 - { name: kernel.event_subscriber }
170
171 wallabag_core.entry.download_images:
172 class: Wallabag\CoreBundle\Helper\DownloadImages
173 arguments:
174 - "@wallabag_core.entry.download_images.client"
175 - "%kernel.root_dir%/../web/assets/images"
176 - '@=service(''craue_config'').get(''wallabag_url'')'
177 - "@logger"
178
179 wallabag_core.entry.download_images.client:
180 class: GuzzleHttp\Client
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
index a1bee173..8a20cbe0 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
@@ -70,7 +70,12 @@ config:
70 # 200_word: 'I read ~200 words per minute' 70 # 200_word: 'I read ~200 words per minute'
71 # 300_word: 'I read ~300 words per minute' 71 # 300_word: 'I read ~300 words per minute'
72 # 400_word: 'I read ~400 words per minute' 72 # 400_word: 'I read ~400 words per minute'
73 action_mark_as_read:
74 # label: 'Where do you to be redirected after mark an article as read?'
75 # redirect_homepage: 'To the homepage'
76 # redirect_current_page: 'To the current page'
73 pocket_consumer_key_label: Brugers nøgle til Pocket for at importere materialer 77 pocket_consumer_key_label: Brugers nøgle til Pocket for at importere materialer
78 # android_configuration: Configure your Android application
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 # help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 # help_items_per_page: "You can change the number of articles displayed on each page." 80 # help_items_per_page: "You can change the number of articles displayed on each page."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'Emailadresse' 99 email_label: 'Emailadresse'
95 # twoFactorAuthentication_label: 'Two factor authentication' 100 # twoFactorAuthentication_label: 'Two factor authentication'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 # title: Delete my account (a.k.a danger zone)
104 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
105 # confirm: Are you really sure? (THIS CAN'T BE UNDONE)
106 # button: Delete my account
107 reset:
108 # title: Reset area (a.k.a danger zone)
109 # description: By hiting buttons below you'll have ability to remove some informations from your account. Be aware that these actions are IRREVERSIBLE.
110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags
112 # entries: Remove ALL entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 # description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'Gammel adgangskode' 116 old_password_label: 'Gammel adgangskode'
@@ -145,6 +162,7 @@ entry:
145 # archived: 'Archived entries' 162 # archived: 'Archived entries'
146 # filtered: 'Filtered entries' 163 # filtered: 'Filtered entries'
147 # filtered_tags: 'Filtered by tags:' 164 # filtered_tags: 'Filtered by tags:'
165 # filtered_search: 'Filtered by search:'
148 # untagged: 'Untagged entries' 166 # untagged: 'Untagged entries'
149 list: 167 list:
150 # number_on_the_page: '{0} There is no entry.|{1} There is one entry.|]1,Inf[ There are %count% entries.' 168 # number_on_the_page: '{0} There is no entry.|{1} There is one entry.|]1,Inf[ There are %count% entries.'
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: 'Har et vist billede' 186 preview_picture_label: 'Har et vist billede'
169 preview_picture_help: 'Forhåndsvis billede' 187 preview_picture_help: 'Forhåndsvis billede'
170 language_label: 'Sprog' 188 language_label: 'Sprog'
189 # http_status_label: 'HTTP status'
171 reading_time: 190 reading_time:
172 label: 'Læsetid i minutter' 191 label: 'Læsetid i minutter'
173 from: 'fra' 192 from: 'fra'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
210 form_new: 229 form_new:
211 url_label: Url 230 url_label: Url
231 search:
232 # placeholder: 'What are you looking for?'
212 edit: 233 edit:
213 # page_title: 'Edit an entry' 234 # page_title: 'Edit an entry'
214 # title_label: 'Title' 235 # title_label: 'Title'
@@ -252,6 +273,9 @@ about:
252howto: 273howto:
253 page_title: 'How-to' 274 page_title: 'How-to'
254 # page_description: 'There are several ways to save an article:' 275 # page_description: 'There are several ways to save an article:'
276 tab_menu:
277 # add_link: "Add a link"
278 # shortcuts: "Use shortcuts"
255 top_menu: 279 top_menu:
256 browser_addons: 'Browserudvidelser' 280 browser_addons: 'Browserudvidelser'
257 mobile_apps: 'Apps' 281 mobile_apps: 'Apps'
@@ -269,6 +293,33 @@ howto:
269 # windows: 'on the Microsoft Store' 293 # windows: 'on the Microsoft Store'
270 bookmarklet: 294 bookmarklet:
271 description: 'Træk dette link til din bogmærkeliste:' 295 description: 'Træk dette link til din bogmærkeliste:'
296 shortcuts:
297 # page_description: Here are the shortcuts available in wallabag.
298 # shortcut: Shortcut
299 # action: Action
300 # all_pages_title: Shortcuts available in all pages
301 # go_unread: Go to unread
302 # go_starred: Go to starred
303 # go_archive: Go to archive
304 # go_all: Go to all entries
305 # go_tags: Go to tags
306 # go_config: Go to config
307 # go_import: Go to import
308 # go_developers: Go to developers
309 # go_howto: Go to howto (this page!)
310 # go_logout: Logout
311 # list_title: Shortcuts available in listing pages
312 # search: Display the search form
313 # article_title: Shortcuts available in entry view
314 # open_original: Open original URL of the entry
315 # toggle_favorite: Toggle star status for the entry
316 # toggle_archive: Toggle read status for the entry
317 # delete: Delete the entry
318 # material_title: Shortcuts available with Material theme only
319 # add_link: Add a new link
320 # hide_form: Hide the current form (search or new link)
321 # arrows_navigation: Navigate through articles
322 # open_article: Display the selected entry
272 323
273quickstart: 324quickstart:
274 # page_title: 'Quickstart' 325 # page_title: 'Quickstart'
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.' 381 # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.'
331 # see_untagged_entries: 'See untagged entries' 382 # see_untagged_entries: 'See untagged entries'
383 new:
384 # add: 'Add'
385 # placeholder: 'You can add several tags, separated by a comma.'
332 386
333import: 387import:
334 # page_title: 'Import' 388 # page_title: 'Import'
@@ -362,6 +416,7 @@ import:
362 # how_to: 'Please select your Readability export and click on the below button to upload and import it.' 416 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
363 worker: 417 worker:
364 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" 418 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
419 # download_images_warning: "You enabled downloading images for your articles. Combined with classic import it can take ages to proceed (or maybe failed). We <strong>strongly recommend</strong> to enable asynchronous import to avoid errors."
365 # firefox: 420 # firefox:
366 # page_title: 'Import > Firefox' 421 # page_title: 'Import > Firefox'
367 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file." 422 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
@@ -374,6 +429,10 @@ import:
374 # page_title: 'Import > Instapaper' 429 # page_title: 'Import > Instapaper'
375 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").' 430 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
376 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.' 431 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
432 pinboard:
433 # page_title: "Import > Pinboard"
434 # description: 'This importer will import all your Instapaper articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").'
435 # how_to: 'Please select your Pinboard export and click on the below button to upload and import it.'
377 436
378developer: 437developer:
379 # page_title: 'Developer' 438 # page_title: 'Developer'
@@ -465,8 +524,10 @@ flashes:
465 rss_updated: 'RSS-oplysninger opdateret' 524 rss_updated: 'RSS-oplysninger opdateret'
466 # tagging_rules_updated: 'Tagging rules updated' 525 # tagging_rules_updated: 'Tagging rules updated'
467 # tagging_rules_deleted: 'Tagging rule deleted' 526 # tagging_rules_deleted: 'Tagging rule deleted'
468 # user_added: 'User "%username%" added'
469 # rss_token_updated: 'RSS token updated' 527 # rss_token_updated: 'RSS token updated'
528 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset
530 # entries_reset: Entries reset
470 entry: 531 entry:
471 notice: 532 notice:
472 # entry_already_saved: 'Entry already saved on %date%' 533 # entry_already_saved: 'Entry already saved on %date%'
@@ -496,3 +557,8 @@ flashes:
496 notice: 557 notice:
497 # client_created: 'New client created.' 558 # client_created: 'New client created.'
498 # client_deleted: 'Client deleted' 559 # client_deleted: 'Client deleted'
560 user:
561 notice:
562 # added: 'User "%username%" added'
563 # updated: 'User "%username%" updated'
564 # deleted: 'User "%username%" deleted'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
index c9625d06..68e9c333 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
@@ -70,7 +70,12 @@ config:
70 200_word: 'Ich lese ~200 Wörter pro Minute' 70 200_word: 'Ich lese ~200 Wörter pro Minute'
71 300_word: 'Ich lese ~300 Wörter pro Minute' 71 300_word: 'Ich lese ~300 Wörter pro Minute'
72 400_word: 'Ich lese ~400 Wörter pro Minute' 72 400_word: 'Ich lese ~400 Wörter pro Minute'
73 action_mark_as_read:
74 label: 'Wohin soll nach dem Gelesenmarkieren eines Artikels weitergeleitet werden?'
75 redirect_homepage: 'Zur Homepage'
76 redirect_current_page: 'Zur aktuellen Seite'
73 pocket_consumer_key_label: Consumer-Key für Pocket, um Inhalte zu importieren 77 pocket_consumer_key_label: Consumer-Key für Pocket, um Inhalte zu importieren
78 android_configuration: Konfiguriere deine Android Application
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 # help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 # help_items_per_page: "You can change the number of articles displayed on each page." 80 # help_items_per_page: "You can change the number of articles displayed on each page."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'E-Mail-Adresse' 99 email_label: 'E-Mail-Adresse'
95 twoFactorAuthentication_label: 'Zwei-Faktor-Authentifizierung' 100 twoFactorAuthentication_label: 'Zwei-Faktor-Authentifizierung'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 title: Lösche mein Konto (a.k.a Gefahrenzone)
104 description: Wenn du dein Konto löschst, werden ALL deine Artikel, ALL deine Tags, ALL deine Anmerkungen und dein Konto dauerhaft gelöscht (kann NICHT RÜCKGÄNGIG gemacht werden). Du wirst anschließend ausgeloggt.
105 confirm: Bist du wirklich sicher? (DIES KANN NICHT RÜCKGÄNGIG GEMACHT WERDEN)
106 button: Lösche mein Konto
107 reset:
108 title: Zurücksetzen (a.k.a Gefahrenzone)
109 description: Beim Nutzen der folgenden Schaltflächenhast du die Möglichkeit, einige Informationen von deinem Konto zu entfernen. Sei dir bewusst, dass dies NICHT RÜCKGÄNGIG zu machen ist.
110 annotations: Entferne ALLE Annotationen
111 tags: Entferne ALLE Tags
112 entries: Entferne ALLE Einträge
113 confirm: Bist du wirklich sicher? (DIES KANN NICHT RÜCKGÄNGIG GEMACHT WERDEN)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 # description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'Altes Kennwort' 116 old_password_label: 'Altes Kennwort'
@@ -145,6 +162,7 @@ entry:
145 archived: 'Archivierte Einträge' 162 archived: 'Archivierte Einträge'
146 filtered: 'Gefilterte Einträge' 163 filtered: 'Gefilterte Einträge'
147 filtered_tags: 'Gefiltert nach Tags:' 164 filtered_tags: 'Gefiltert nach Tags:'
165 # filtered_search: 'Filtered by search:'
148 untagged: 'Nicht getaggte Einträge' 166 untagged: 'Nicht getaggte Einträge'
149 list: 167 list:
150 number_on_the_page: '{0} Es gibt keine Einträge.|{1} Es gibt einen Eintrag.|]1,Inf[ Es gibt %count% Einträge.' 168 number_on_the_page: '{0} Es gibt keine Einträge.|{1} Es gibt einen Eintrag.|]1,Inf[ Es gibt %count% Einträge.'
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: 'Vorschaubild vorhanden' 186 preview_picture_label: 'Vorschaubild vorhanden'
169 preview_picture_help: 'Vorschaubild' 187 preview_picture_help: 'Vorschaubild'
170 language_label: 'Sprache' 188 language_label: 'Sprache'
189 # http_status_label: 'HTTP status'
171 reading_time: 190 reading_time:
172 label: 'Lesezeit in Minuten' 191 label: 'Lesezeit in Minuten'
173 from: 'von' 192 from: 'von'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'https://website.de' 228 placeholder: 'https://website.de'
210 form_new: 229 form_new:
211 url_label: URL 230 url_label: URL
231 search:
232 # placeholder: 'What are you looking for?'
212 edit: 233 edit:
213 page_title: 'Eintrag bearbeiten' 234 page_title: 'Eintrag bearbeiten'
214 title_label: 'Titel' 235 title_label: 'Titel'
@@ -252,6 +273,9 @@ about:
252howto: 273howto:
253 page_title: 'How-To' 274 page_title: 'How-To'
254 page_description: 'Es gibt mehrere Möglichkeiten, einen Artikel zu speichern:' 275 page_description: 'Es gibt mehrere Möglichkeiten, einen Artikel zu speichern:'
276 tab_menu:
277 # add_link: "Add a link"
278 # shortcuts: "Use shortcuts"
255 top_menu: 279 top_menu:
256 browser_addons: 'Browser-Erweiterungen' 280 browser_addons: 'Browser-Erweiterungen'
257 mobile_apps: 'Apps' 281 mobile_apps: 'Apps'
@@ -269,6 +293,33 @@ howto:
269 windows: 'im Microsoft-Store' 293 windows: 'im Microsoft-Store'
270 bookmarklet: 294 bookmarklet:
271 description: 'Ziehe diesen Link in deine Lesezeichenleiste:' 295 description: 'Ziehe diesen Link in deine Lesezeichenleiste:'
296 shortcuts:
297 # page_description: Here are the shortcuts available in wallabag.
298 # shortcut: Shortcut
299 # action: Action
300 # all_pages_title: Shortcuts available in all pages
301 # go_unread: Go to unread
302 # go_starred: Go to starred
303 # go_archive: Go to archive
304 # go_all: Go to all entries
305 # go_tags: Go to tags
306 # go_config: Go to config
307 # go_import: Go to import
308 # go_developers: Go to developers
309 # go_howto: Go to howto (this page!)
310 # go_logout: Logout
311 # list_title: Shortcuts available in listing pages
312 # search: Display the search form
313 # article_title: Shortcuts available in entry view
314 # open_original: Open original URL of the entry
315 # toggle_favorite: Toggle star status for the entry
316 # toggle_archive: Toggle read status for the entry
317 # delete: Delete the entry
318 # material_title: Shortcuts available with Material theme only
319 # add_link: Add a new link
320 # hide_form: Hide the current form (search or new link)
321 # arrows_navigation: Navigate through articles
322 # open_article: Display the selected entry
272 323
273quickstart: 324quickstart:
274 page_title: 'Schnelleinstieg' 325 page_title: 'Schnelleinstieg'
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 number_on_the_page: '{0} Es gibt keine Tags.|{1} Es gibt einen Tag.|]1,Inf[ Es gibt %count% Tags.' 381 number_on_the_page: '{0} Es gibt keine Tags.|{1} Es gibt einen Tag.|]1,Inf[ Es gibt %count% Tags.'
331 see_untagged_entries: 'Zeige nicht getaggte Einträge' 382 see_untagged_entries: 'Zeige nicht getaggte Einträge'
383 new:
384 # add: 'Add'
385 # placeholder: 'You can add several tags, separated by a comma.'
332 386
333import: 387import:
334 page_title: 'Importieren' 388 page_title: 'Importieren'
@@ -362,6 +416,7 @@ import:
362 how_to: 'Bitte wähle deinen Readability Export aus und klicke den unteren Button für das Hochladen und Importieren dessen.' 416 how_to: 'Bitte wähle deinen Readability Export aus und klicke den unteren Button für das Hochladen und Importieren dessen.'
363 worker: 417 worker:
364 enabled: "Der Import erfolgt asynchron. Sobald der Import gestartet ist, wird diese Aufgabe extern abgearbeitet. Der aktuelle Service dafür ist:" 418 enabled: "Der Import erfolgt asynchron. Sobald der Import gestartet ist, wird diese Aufgabe extern abgearbeitet. Der aktuelle Service dafür ist:"
419 download_images_warning: "Du hast das Herunterladen von Bildern für deine Artikel aktiviert. Verbunden mit dem klassischen Import kann es ewig dauern fortzufahren (oder sogar fehlschlagen). Wir <strong>empfehlen</strong> den asynchronen Import zu aktivieren, um Fehler zu vermeiden."
365 firefox: 420 firefox:
366 page_title: 'Aus Firefox importieren' 421 page_title: 'Aus Firefox importieren'
367 description: "Dieser Import wird all deine Lesezeichen aus Firefox importieren. Gehe zu deinen Lesezeichen (Strg+Shift+O), dann auf \"Importen und Sichern\", wähle \"Sichern…\". Du erhälst eine .json Datei." 422 description: "Dieser Import wird all deine Lesezeichen aus Firefox importieren. Gehe zu deinen Lesezeichen (Strg+Shift+O), dann auf \"Importen und Sichern\", wähle \"Sichern…\". Du erhälst eine .json Datei."
@@ -374,6 +429,10 @@ import:
374 page_title: 'Aus Instapaper importieren' 429 page_title: 'Aus Instapaper importieren'
375 description: 'Dieser Import wird all deine Instapaper Artikel importieren. Auf der Einstellungsseite (https://www.instapaper.com/user) klickst du auf "Download .CSV Datei" in dem Abschnitt "Export". Eine CSV Datei wird heruntergeladen (z.B. "instapaper-export.csv").' 430 description: 'Dieser Import wird all deine Instapaper Artikel importieren. Auf der Einstellungsseite (https://www.instapaper.com/user) klickst du auf "Download .CSV Datei" in dem Abschnitt "Export". Eine CSV Datei wird heruntergeladen (z.B. "instapaper-export.csv").'
376 how_to: "Bitte wähle deine Instapaper Sicherungsdatei aus und klicke den nachfolgenden Button zum Importieren." 431 how_to: "Bitte wähle deine Instapaper Sicherungsdatei aus und klicke den nachfolgenden Button zum Importieren."
432 pinboard:
433 page_title: "Aus Pinboard importieren"
434 description: 'Dieser Import wird all deine Pinboard Artikel importieren. Auf der Seite Backup (https://pinboard.in/settings/backup) klickst du auf "JSON" in dem Abschnitt "Lesezeichen". Eine JSON Datei wird dann heruntergeladen (z.B. "pinboard_export").'
435 how_to: 'Bitte wähle deinen Pinboard Export aus und klicke den nachfolgenden Button zum Importieren.'
377 436
378developer: 437developer:
379 page_title: 'Entwickler' 438 page_title: 'Entwickler'
@@ -453,7 +512,7 @@ user:
453 back_to_list: Zurück zur Liste 512 back_to_list: Zurück zur Liste
454 513
455error: 514error:
456 # page_title: An error occurred 515 page_title: Ein Fehler ist aufgetreten
457 516
458flashes: 517flashes:
459 config: 518 config:
@@ -465,8 +524,10 @@ flashes:
465 rss_updated: 'RSS-Informationen aktualisiert' 524 rss_updated: 'RSS-Informationen aktualisiert'
466 tagging_rules_updated: 'Tagging-Regeln aktualisiert' 525 tagging_rules_updated: 'Tagging-Regeln aktualisiert'
467 tagging_rules_deleted: 'Tagging-Regel gelöscht' 526 tagging_rules_deleted: 'Tagging-Regel gelöscht'
468 user_added: 'Benutzer "%username%" erstellt'
469 rss_token_updated: 'RSS-Token aktualisiert' 527 rss_token_updated: 'RSS-Token aktualisiert'
528 annotations_reset: Anmerkungen zurücksetzen
529 tags_reset: Tags zurücksetzen
530 entries_reset: Einträge zurücksetzen
470 entry: 531 entry:
471 notice: 532 notice:
472 entry_already_saved: 'Eintrag bereits am %date% gespeichert' 533 entry_already_saved: 'Eintrag bereits am %date% gespeichert'
@@ -496,3 +557,8 @@ flashes:
496 notice: 557 notice:
497 client_created: 'Neuer Client erstellt.' 558 client_created: 'Neuer Client erstellt.'
498 client_deleted: 'Client gelöscht' 559 client_deleted: 'Client gelöscht'
560 user:
561 notice:
562 added: 'Benutzer "%username%" hinzugefügt'
563 updated: 'Benutzer "%username%" aktualisiert'
564 deleted: 'Benutzer "%username%" gelöscht'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
index 139cdc24..9e13ad0e 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
@@ -70,7 +70,12 @@ config:
70 200_word: 'I read ~200 words per minute' 70 200_word: 'I read ~200 words per minute'
71 300_word: 'I read ~300 words per minute' 71 300_word: 'I read ~300 words per minute'
72 400_word: 'I read ~400 words per minute' 72 400_word: 'I read ~400 words per minute'
73 action_mark_as_read:
74 label: 'Where do you want to be redirected after mark an article as read?'
75 redirect_homepage: 'To the homepage'
76 redirect_current_page: 'To the current page'
73 pocket_consumer_key_label: Consumer key for Pocket to import contents 77 pocket_consumer_key_label: Consumer key for Pocket to import contents
78 android_configuration: Configure your Android application
74 help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 help_items_per_page: "You can change the number of articles displayed on each page." 80 help_items_per_page: "You can change the number of articles displayed on each page."
76 help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'Email' 99 email_label: 'Email'
95 twoFactorAuthentication_label: 'Two factor authentication' 100 twoFactorAuthentication_label: 'Two factor authentication'
96 help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 title: Delete my account (a.k.a danger zone)
104 description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
105 confirm: Are you really sure? (THIS CAN'T BE UNDONE)
106 button: Delete my account
107 reset:
108 title: Reset area (a.k.a danger zone)
109 description: By hitting buttons below you'll have ability to remove some information from your account. Be aware that these actions are IRREVERSIBLE.
110 annotations: Remove ALL annotations
111 tags: Remove ALL tags
112 entries: Remove ALL entries
113 confirm: Are you really sure? (THIS CAN'T BE UNDONE)
97 form_password: 114 form_password:
98 description: "You can change your password here. Your new password should by at least 8 characters long." 115 description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'Current password' 116 old_password_label: 'Current password'
@@ -145,6 +162,7 @@ entry:
145 archived: 'Archived entries' 162 archived: 'Archived entries'
146 filtered: 'Filtered entries' 163 filtered: 'Filtered entries'
147 filtered_tags: 'Filtered by tags:' 164 filtered_tags: 'Filtered by tags:'
165 filtered_search: 'Filtered by search:'
148 untagged: 'Untagged entries' 166 untagged: 'Untagged entries'
149 list: 167 list:
150 number_on_the_page: '{0} There are no entries.|{1} There is one entry.|]1,Inf[ There are %count% entries.' 168 number_on_the_page: '{0} There are no entries.|{1} There is one entry.|]1,Inf[ There are %count% entries.'
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: 'Has a preview picture' 186 preview_picture_label: 'Has a preview picture'
169 preview_picture_help: 'Preview picture' 187 preview_picture_help: 'Preview picture'
170 language_label: 'Language' 188 language_label: 'Language'
189 http_status_label: 'HTTP status'
171 reading_time: 190 reading_time:
172 label: 'Reading time in minutes' 191 label: 'Reading time in minutes'
173 from: 'from' 192 from: 'from'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
210 form_new: 229 form_new:
211 url_label: Url 230 url_label: Url
231 search:
232 placeholder: 'What are you looking for?'
212 edit: 233 edit:
213 page_title: 'Edit an entry' 234 page_title: 'Edit an entry'
214 title_label: 'Title' 235 title_label: 'Title'
@@ -251,6 +272,9 @@ about:
251 272
252howto: 273howto:
253 page_title: 'How to' 274 page_title: 'How to'
275 tab_menu:
276 add_link: "Add a link"
277 shortcuts: "Use shortcuts"
254 page_description: 'There are several ways to save an article:' 278 page_description: 'There are several ways to save an article:'
255 top_menu: 279 top_menu:
256 browser_addons: 'Browser addons' 280 browser_addons: 'Browser addons'
@@ -269,6 +293,33 @@ howto:
269 windows: 'on the Microsoft Store' 293 windows: 'on the Microsoft Store'
270 bookmarklet: 294 bookmarklet:
271 description: 'Drag & drop this link to your bookmarks bar:' 295 description: 'Drag & drop this link to your bookmarks bar:'
296 shortcuts:
297 page_description: Here are the shortcuts available in wallabag.
298 shortcut: Shortcut
299 action: Action
300 all_pages_title: Shortcuts available in all pages
301 go_unread: Go to unread
302 go_starred: Go to starred
303 go_archive: Go to archive
304 go_all: Go to all entries
305 go_tags: Go to tags
306 go_config: Go to config
307 go_import: Go to import
308 go_developers: Go to developers
309 go_howto: Go to howto (this page!)
310 go_logout: Logout
311 list_title: Shortcuts available in listing pages
312 search: Display the search form
313 article_title: Shortcuts available in entry view
314 open_original: Open original URL of the entry
315 toggle_favorite: Toggle star status for the entry
316 toggle_archive: Toggle read status for the entry
317 delete: Delete the entry
318 material_title: Shortcuts available with Material theme only
319 add_link: Add a new link
320 hide_form: Hide the current form (search or new link)
321 arrows_navigation: Navigate through articles
322 open_article: Display the selected entry
272 323
273quickstart: 324quickstart:
274 page_title: 'Quickstart' 325 page_title: 'Quickstart'
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 number_on_the_page: '{0} There are no tags.|{1} There is one tag.|]1,Inf[ There are %count% tags.' 381 number_on_the_page: '{0} There are no tags.|{1} There is one tag.|]1,Inf[ There are %count% tags.'
331 see_untagged_entries: 'See untagged entries' 382 see_untagged_entries: 'See untagged entries'
383 new:
384 add: 'Add'
385 placeholder: 'You can add several tags, separated by a comma.'
332 386
333import: 387import:
334 page_title: 'Import' 388 page_title: 'Import'
@@ -362,6 +416,7 @@ import:
362 how_to: 'Please select your Readability export and click on the below button to upload and import it.' 416 how_to: 'Please select your Readability export and click on the below button to upload and import it.'
363 worker: 417 worker:
364 enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" 418 enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
419 download_images_warning: "You enabled downloading images for your articles. Combined with classic import it can take ages to proceed (or maybe failed). We <strong>strongly recommend</strong> to enable asynchronous import to avoid errors."
365 firefox: 420 firefox:
366 page_title: 'Import > Firefox' 421 page_title: 'Import > Firefox'
367 description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file." 422 description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
@@ -374,6 +429,10 @@ import:
374 page_title: 'Import > Instapaper' 429 page_title: 'Import > Instapaper'
375 description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").' 430 description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
376 how_to: 'Please select your Instapaper export and click on the below button to upload and import it.' 431 how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
432 pinboard:
433 page_title: "Import > Pinboard"
434 description: 'This importer will import all your Pinboard articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").'
435 how_to: 'Please select your Pinboard export and click on the below button to upload and import it.'
377 436
378developer: 437developer:
379 page_title: 'Developer' 438 page_title: 'Developer'
@@ -466,6 +525,9 @@ flashes:
466 tagging_rules_updated: 'Tagging rules updated' 525 tagging_rules_updated: 'Tagging rules updated'
467 tagging_rules_deleted: 'Tagging rule deleted' 526 tagging_rules_deleted: 'Tagging rule deleted'
468 rss_token_updated: 'RSS token updated' 527 rss_token_updated: 'RSS token updated'
528 annotations_reset: Annotations reset
529 tags_reset: Tags reset
530 entries_reset: Entries reset
469 entry: 531 entry:
470 notice: 532 notice:
471 entry_already_saved: 'Entry already saved on %date%' 533 entry_already_saved: 'Entry already saved on %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
index 70e64bec..b8764876 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
@@ -70,7 +70,12 @@ config:
70 200_word: 'Leo ~200 palabras por minuto' 70 200_word: 'Leo ~200 palabras por minuto'
71 300_word: 'Leo ~300 palabras por minuto' 71 300_word: 'Leo ~300 palabras por minuto'
72 400_word: 'Leo ~400 palabras por minuto' 72 400_word: 'Leo ~400 palabras por minuto'
73 action_mark_as_read:
74 # label: 'Where do you to be redirected after mark an article as read?'
75 # redirect_homepage: 'To the homepage'
76 # redirect_current_page: 'To the current page'
73 # pocket_consumer_key_label: Consumer key for Pocket to import contents 77 # pocket_consumer_key_label: Consumer key for Pocket to import contents
78 # android_configuration: Configure your Android application
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 # help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 # help_items_per_page: "You can change the number of articles displayed on each page." 80 # help_items_per_page: "You can change the number of articles displayed on each page."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'Direccion e-mail' 99 email_label: 'Direccion e-mail'
95 twoFactorAuthentication_label: 'Autentificación de dos factores' 100 twoFactorAuthentication_label: 'Autentificación de dos factores'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 # title: Delete my account (a.k.a danger zone)
104 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
105 # confirm: Are you really sure? (THIS CAN'T BE UNDONE)
106 # button: Delete my account
107 reset:
108 # title: Reset area (a.k.a danger zone)
109 # description: By hiting buttons below you'll have ability to remove some informations from your account. Be aware that these actions are IRREVERSIBLE.
110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags
112 # entries: Remove ALL entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 # description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'Contraseña actual' 116 old_password_label: 'Contraseña actual'
@@ -145,6 +162,7 @@ entry:
145 archived: 'Artículos archivados' 162 archived: 'Artículos archivados'
146 filtered: 'Artículos filtrados' 163 filtered: 'Artículos filtrados'
147 # filtered_tags: 'Filtered by tags:' 164 # filtered_tags: 'Filtered by tags:'
165 # filtered_search: 'Filtered by search:'
148 # untagged: 'Untagged entries' 166 # untagged: 'Untagged entries'
149 list: 167 list:
150 number_on_the_page: '{0} No hay artículos.|{1} Hay un artículo.|]1,Inf[ Hay %count% artículos.' 168 number_on_the_page: '{0} No hay artículos.|{1} Hay un artículo.|]1,Inf[ Hay %count% artículos.'
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: 'Hay una foto' 186 preview_picture_label: 'Hay una foto'
169 preview_picture_help: 'Foto de preview' 187 preview_picture_help: 'Foto de preview'
170 language_label: 'Idioma' 188 language_label: 'Idioma'
189 # http_status_label: 'HTTP status'
171 reading_time: 190 reading_time:
172 label: 'Duración de lectura en minutos' 191 label: 'Duración de lectura en minutos'
173 from: 'de' 192 from: 'de'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
210 form_new: 229 form_new:
211 url_label: Url 230 url_label: Url
231 search:
232 # placeholder: 'What are you looking for?'
212 edit: 233 edit:
213 page_title: 'Editar un artículo' 234 page_title: 'Editar un artículo'
214 title_label: 'Título' 235 title_label: 'Título'
@@ -252,6 +273,9 @@ about:
252howto: 273howto:
253 page_title: 'Ayuda' 274 page_title: 'Ayuda'
254 page_description: 'Hay muchas maneras para guardar un artículo:' 275 page_description: 'Hay muchas maneras para guardar un artículo:'
276 tab_menu:
277 # add_link: "Add a link"
278 # shortcuts: "Use shortcuts"
255 top_menu: 279 top_menu:
256 browser_addons: 'Extensiones de navigador' 280 browser_addons: 'Extensiones de navigador'
257 mobile_apps: 'Aplicaciones para smartphone' 281 mobile_apps: 'Aplicaciones para smartphone'
@@ -269,6 +293,33 @@ howto:
269 windows: 'por la tienda de Microsoft' 293 windows: 'por la tienda de Microsoft'
270 bookmarklet: 294 bookmarklet:
271 description: 'Desplazar y soltar este link en la barra de marcadores :' 295 description: 'Desplazar y soltar este link en la barra de marcadores :'
296 shortcuts:
297 # page_description: Here are the shortcuts available in wallabag.
298 # shortcut: Shortcut
299 # action: Action
300 # all_pages_title: Shortcuts available in all pages
301 # go_unread: Go to unread
302 # go_starred: Go to starred
303 # go_archive: Go to archive
304 # go_all: Go to all entries
305 # go_tags: Go to tags
306 # go_config: Go to config
307 # go_import: Go to import
308 # go_developers: Go to developers
309 # go_howto: Go to howto (this page!)
310 # go_logout: Logout
311 # list_title: Shortcuts available in listing pages
312 # search: Display the search form
313 # article_title: Shortcuts available in entry view
314 # open_original: Open original URL of the entry
315 # toggle_favorite: Toggle star status for the entry
316 # toggle_archive: Toggle read status for the entry
317 # delete: Delete the entry
318 # material_title: Shortcuts available with Material theme only
319 # add_link: Add a new link
320 # hide_form: Hide the current form (search or new link)
321 # arrows_navigation: Navigate through articles
322 # open_article: Display the selected entry
272 323
273quickstart: 324quickstart:
274 page_title: 'Comienzo rápido' 325 page_title: 'Comienzo rápido'
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 number_on_the_page: '{0} No hay ninguna etiqueta.|{1} Hay una etiqueta.|]1,Inf[ Hay %count% etiquetas.' 381 number_on_the_page: '{0} No hay ninguna etiqueta.|{1} Hay una etiqueta.|]1,Inf[ Hay %count% etiquetas.'
331 # see_untagged_entries: 'See untagged entries' 382 # see_untagged_entries: 'See untagged entries'
383 new:
384 # add: 'Add'
385 # placeholder: 'You can add several tags, separated by a comma.'
332 386
333import: 387import:
334 page_title: 'Importar' 388 page_title: 'Importar'
@@ -362,6 +416,7 @@ import:
362 # how_to: 'Please select your Readability export and click on the below button to upload and import it.' 416 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
363 worker: 417 worker:
364 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" 418 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
419 # download_images_warning: "You enabled downloading images for your articles. Combined with classic import it can take ages to proceed (or maybe failed). We <strong>strongly recommend</strong> to enable asynchronous import to avoid errors."
365 firefox: 420 firefox:
366 page_title: 'Importar > Firefox' 421 page_title: 'Importar > Firefox'
367 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file." 422 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
@@ -374,6 +429,10 @@ import:
374 page_title: 'Importar > Instapaper' 429 page_title: 'Importar > Instapaper'
375 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").' 430 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
376 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.' 431 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
432 pinboard:
433 page_title: "Importar > Pinboard"
434 # description: 'This importer will import all your Instapaper articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").'
435 # how_to: 'Please select your Pinboard export and click on the below button to upload and import it.'
377 436
378developer: 437developer:
379 page_title: 'Promotor' 438 page_title: 'Promotor'
@@ -465,8 +524,10 @@ flashes:
465 rss_updated: 'La configuración de los feeds RSS ha sido actualizada' 524 rss_updated: 'La configuración de los feeds RSS ha sido actualizada'
466 tagging_rules_updated: 'Regla de etiquetado borrada' 525 tagging_rules_updated: 'Regla de etiquetado borrada'
467 tagging_rules_deleted: 'Regla de etiquetado actualizada' 526 tagging_rules_deleted: 'Regla de etiquetado actualizada'
468 user_added: 'Usuario "%username%" añadido'
469 rss_token_updated: 'RSS token actualizado' 527 rss_token_updated: 'RSS token actualizado'
528 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset
530 # entries_reset: Entries reset
470 entry: 531 entry:
471 notice: 532 notice:
472 entry_already_saved: 'Entrada ya guardada por %fecha%' 533 entry_already_saved: 'Entrada ya guardada por %fecha%'
@@ -496,3 +557,8 @@ flashes:
496 notice: 557 notice:
497 client_created: 'Nuevo cliente creado.' 558 client_created: 'Nuevo cliente creado.'
498 client_deleted: 'Cliente suprimido' 559 client_deleted: 'Cliente suprimido'
560 user:
561 notice:
562 # added: 'User "%username%" added'
563 # updated: 'User "%username%" updated'
564 # deleted: 'User "%username%" deleted'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
index 75359901..e1bfcade 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
@@ -70,7 +70,12 @@ config:
70 200_word: 'من تقریباً ۲۰۰ واژه را در دقیقه می‌خوانم' 70 200_word: 'من تقریباً ۲۰۰ واژه را در دقیقه می‌خوانم'
71 300_word: 'من تقریباً ۳۰۰ واژه را در دقیقه می‌خوانم' 71 300_word: 'من تقریباً ۳۰۰ واژه را در دقیقه می‌خوانم'
72 400_word: 'من تقریباً ۴۰۰ واژه را در دقیقه می‌خوانم' 72 400_word: 'من تقریباً ۴۰۰ واژه را در دقیقه می‌خوانم'
73 action_mark_as_read:
74 # label: 'Where do you to be redirected after mark an article as read?'
75 # redirect_homepage: 'To the homepage'
76 # redirect_current_page: 'To the current page'
73 pocket_consumer_key_label: کلید کاربری Pocket برای درون‌ریزی مطالب 77 pocket_consumer_key_label: کلید کاربری Pocket برای درون‌ریزی مطالب
78 # android_configuration: Configure your Android application
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 # help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 # help_items_per_page: "You can change the number of articles displayed on each page." 80 # help_items_per_page: "You can change the number of articles displayed on each page."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'نشانی ایمیل' 99 email_label: 'نشانی ایمیل'
95 twoFactorAuthentication_label: 'تأیید ۲مرحله‌ای' 100 twoFactorAuthentication_label: 'تأیید ۲مرحله‌ای'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 # title: Delete my account (a.k.a danger zone)
104 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
105 # confirm: Are you really sure? (THIS CAN'T BE UNDONE)
106 # button: Delete my account
107 reset:
108 # title: Reset area (a.k.a danger zone)
109 # description: By hiting buttons below you'll have ability to remove some informations from your account. Be aware that these actions are IRREVERSIBLE.
110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags
112 # entries: Remove ALL entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 # description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'رمز قدیمی' 116 old_password_label: 'رمز قدیمی'
@@ -145,6 +162,7 @@ entry:
145 archived: 'مقاله‌های بایگانی‌شده' 162 archived: 'مقاله‌های بایگانی‌شده'
146 filtered: 'مقاله‌های فیلترشده' 163 filtered: 'مقاله‌های فیلترشده'
147 # filtered_tags: 'Filtered by tags:' 164 # filtered_tags: 'Filtered by tags:'
165 # filtered_search: 'Filtered by search:'
148 # untagged: 'Untagged entries' 166 # untagged: 'Untagged entries'
149 list: 167 list:
150 number_on_the_page: '{0} هیج مقاله‌ای نیست.|{1} یک مقاله هست.|]1,Inf[ %count% مقاله هست.' 168 number_on_the_page: '{0} هیج مقاله‌ای نیست.|{1} یک مقاله هست.|]1,Inf[ %count% مقاله هست.'
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: 'دارای عکس پیش‌نمایش' 186 preview_picture_label: 'دارای عکس پیش‌نمایش'
169 preview_picture_help: 'پیش‌نمایش عکس' 187 preview_picture_help: 'پیش‌نمایش عکس'
170 language_label: 'زبان' 188 language_label: 'زبان'
189 # http_status_label: 'HTTP status'
171 reading_time: 190 reading_time:
172 label: 'زمان خواندن به دقیقه' 191 label: 'زمان خواندن به دقیقه'
173 from: 'از' 192 from: 'از'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
210 form_new: 229 form_new:
211 url_label: نشانی 230 url_label: نشانی
231 search:
232 # placeholder: 'What are you looking for?'
212 edit: 233 edit:
213 page_title: 'ویرایش مقاله' 234 page_title: 'ویرایش مقاله'
214 title_label: 'عنوان' 235 title_label: 'عنوان'
@@ -252,6 +273,9 @@ about:
252howto: 273howto:
253 page_title: 'خودآموز' 274 page_title: 'خودآموز'
254 page_description: 'راه‌های زیادی برای ذخیرهٔ مقاله‌ها هست:' 275 page_description: 'راه‌های زیادی برای ذخیرهٔ مقاله‌ها هست:'
276 tab_menu:
277 # add_link: "Add a link"
278 # shortcuts: "Use shortcuts"
255 top_menu: 279 top_menu:
256 browser_addons: 'افزونه برای مرورگرها' 280 browser_addons: 'افزونه برای مرورگرها'
257 mobile_apps: 'برنامه‌های موبایل' 281 mobile_apps: 'برنامه‌های موبایل'
@@ -269,6 +293,33 @@ howto:
269 windows: 'از راه Microsoft Store' 293 windows: 'از راه Microsoft Store'
270 bookmarklet: 294 bookmarklet:
271 description: 'این پیوند را به نوار بوک‌مارک مرورگرتان بکشید:' 295 description: 'این پیوند را به نوار بوک‌مارک مرورگرتان بکشید:'
296 shortcuts:
297 # page_description: Here are the shortcuts available in wallabag.
298 # shortcut: Shortcut
299 # action: Action
300 # all_pages_title: Shortcuts available in all pages
301 # go_unread: Go to unread
302 # go_starred: Go to starred
303 # go_archive: Go to archive
304 # go_all: Go to all entries
305 # go_tags: Go to tags
306 # go_config: Go to config
307 # go_import: Go to import
308 # go_developers: Go to developers
309 # go_howto: Go to howto (this page!)
310 # go_logout: Logout
311 # list_title: Shortcuts available in listing pages
312 # search: Display the search form
313 # article_title: Shortcuts available in entry view
314 # open_original: Open original URL of the entry
315 # toggle_favorite: Toggle star status for the entry
316 # toggle_archive: Toggle read status for the entry
317 # delete: Delete the entry
318 # material_title: Shortcuts available with Material theme only
319 # add_link: Add a new link
320 # hide_form: Hide the current form (search or new link)
321 # arrows_navigation: Navigate through articles
322 # open_article: Display the selected entry
272 323
273quickstart: 324quickstart:
274 page_title: 'Quickstart' 325 page_title: 'Quickstart'
@@ -279,6 +330,7 @@ quickstart:
279 paragraph_2: 'ادامه دهید!' 330 paragraph_2: 'ادامه دهید!'
280 configure: 331 configure:
281 title: 'برنامه را تنظیم کنید' 332 title: 'برنامه را تنظیم کنید'
333 # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.'
282 language: 'زبان و نمای برنامه را تغییر دهید' 334 language: 'زبان و نمای برنامه را تغییر دهید'
283 rss: 'خوراک آر-اس-اس را فعال کنید' 335 rss: 'خوراک آر-اس-اس را فعال کنید'
284 tagging_rules: 'قانون‌های برچسب‌گذاری خودکار مقاله‌هایتان را تعریف کنید' 336 tagging_rules: 'قانون‌های برچسب‌گذاری خودکار مقاله‌هایتان را تعریف کنید'
@@ -328,6 +380,9 @@ tag:
328 list: 380 list:
329 number_on_the_page: '{0} هیچ برچسبی نیست.|{1} یک برچسب هست.|]1,Inf[ %count% برچسب هست.' 381 number_on_the_page: '{0} هیچ برچسبی نیست.|{1} یک برچسب هست.|]1,Inf[ %count% برچسب هست.'
330 # see_untagged_entries: 'See untagged entries' 382 # see_untagged_entries: 'See untagged entries'
383 new:
384 # add: 'Add'
385 # placeholder: 'You can add several tags, separated by a comma.'
331 386
332import: 387import:
333 page_title: 'درون‌ریزی' 388 page_title: 'درون‌ریزی'
@@ -361,6 +416,7 @@ import:
361 # how_to: 'Please select your Readability export and click on the below button to upload and import it.' 416 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
362 worker: 417 worker:
363 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" 418 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
419 # download_images_warning: "You enabled downloading images for your articles. Combined with classic import it can take ages to proceed (or maybe failed). We <strong>strongly recommend</strong> to enable asynchronous import to avoid errors."
364 firefox: 420 firefox:
365 page_title: 'درون‌ریزی > Firefox' 421 page_title: 'درون‌ریزی > Firefox'
366 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file." 422 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
@@ -373,6 +429,10 @@ import:
373 page_title: 'درون‌ریزی > Instapaper' 429 page_title: 'درون‌ریزی > Instapaper'
374 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").' 430 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
375 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.' 431 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
432 pinboard:
433 # page_title: "Import > Pinboard"
434 # description: 'This importer will import all your Instapaper articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").'
435 # how_to: 'Please select your Pinboard export and click on the below button to upload and import it.'
376 436
377developer: 437developer:
378 # page_title: 'Developer' 438 # page_title: 'Developer'
@@ -464,8 +524,10 @@ flashes:
464 rss_updated: 'اطلاعات آر-اس-اس به‌روز شد' 524 rss_updated: 'اطلاعات آر-اس-اس به‌روز شد'
465 tagging_rules_updated: 'برچسب‌گذاری خودکار به‌روز شد' 525 tagging_rules_updated: 'برچسب‌گذاری خودکار به‌روز شد'
466 tagging_rules_deleted: 'قانون برچسب‌گذاری پاک شد' 526 tagging_rules_deleted: 'قانون برچسب‌گذاری پاک شد'
467 user_added: 'کابر "%username%" افزوده شد'
468 rss_token_updated: 'کد آر-اس-اس به‌روز شد' 527 rss_token_updated: 'کد آر-اس-اس به‌روز شد'
528 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset
530 # entries_reset: Entries reset
469 entry: 531 entry:
470 notice: 532 notice:
471 entry_already_saved: 'این مقاله در تاریخ %date% ذخیره شده بود' 533 entry_already_saved: 'این مقاله در تاریخ %date% ذخیره شده بود'
@@ -495,3 +557,8 @@ flashes:
495 notice: 557 notice:
496 # client_created: 'New client created.' 558 # client_created: 'New client created.'
497 # client_deleted: 'Client deleted' 559 # client_deleted: 'Client deleted'
560 user:
561 notice:
562 # added: 'User "%username%" added'
563 # updated: 'User "%username%" updated'
564 # deleted: 'User "%username%" deleted'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
index f2c9d8db..2e4f4f43 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
@@ -70,7 +70,12 @@ config:
70 200_word: "Je lis environ 200 mots par minute" 70 200_word: "Je lis environ 200 mots par minute"
71 300_word: "Je lis environ 300 mots par minute" 71 300_word: "Je lis environ 300 mots par minute"
72 400_word: "Je lis environ 400 mots par minute" 72 400_word: "Je lis environ 400 mots par minute"
73 action_mark_as_read:
74 label: 'Où souhaitez-vous être redirigé après avoir marqué un article comme lu ?'
75 redirect_homepage: "À la page d'accueil"
76 redirect_current_page: 'À la page courante'
73 pocket_consumer_key_label: Clé d’authentification Pocket pour importer les données 77 pocket_consumer_key_label: Clé d’authentification Pocket pour importer les données
78 android_configuration: Configurez votre application Android
74 help_theme: "L'affichage de wallabag est personnalisable. C'est ici que vous choisissez le thème que vous préférez." 79 help_theme: "L'affichage de wallabag est personnalisable. C'est ici que vous choisissez le thème que vous préférez."
75 help_items_per_page: "Vous pouvez définir le nombre d'articles affichés sur chaque page." 80 help_items_per_page: "Vous pouvez définir le nombre d'articles affichés sur chaque page."
76 help_reading_speed: "wallabag calcule une durée de lecture pour chaque article. Vous pouvez définir ici, grâce à cette liste déroulante, si vous lisez plus ou moins vite. wallabag recalculera la durée de lecture de chaque article." 81 help_reading_speed: "wallabag calcule une durée de lecture pour chaque article. Vous pouvez définir ici, grâce à cette liste déroulante, si vous lisez plus ou moins vite. wallabag recalculera la durée de lecture de chaque article."
@@ -94,6 +99,18 @@ config:
94 email_label: "Adresse courriel" 99 email_label: "Adresse courriel"
95 twoFactorAuthentication_label: "Double authentification" 100 twoFactorAuthentication_label: "Double authentification"
96 help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email." 101 help_twoFactorAuthentication: "Si vous activez 2FA, à chaque tentative de connexion à wallabag, vous recevrez un code par email."
102 delete:
103 title: Supprimer mon compte (attention danger !)
104 description: Si vous confirmez la suppression de votre compte, TOUS les articles, TOUS les tags, TOUTES les annotations et votre compte seront DÉFINITIVEMENT supprimé (c'est IRRÉVERSIBLE). Vous serez ensuite déconnecté.
105 confirm: Vous êtes vraiment sûr ? (C'EST IRRÉVERSIBLE)
106 button: 'Supprimer mon compte'
107 reset:
108 title: Réinitialisation (attention danger !)
109 description: En cliquant sur les boutons ci-dessous vous avez la possibilité de supprimer certaines informations de votre compte. Attention, ces actions sont IRRÉVERSIBLES !
110 annotations: Supprimer TOUTES les annotations
111 tags: Supprimer TOUS les tags
112 entries: Supprimer TOUS les articles
113 confirm: Êtes-vous vraiment vraiment sûr ? (C'EST IRRÉVERSIBLE)
97 form_password: 114 form_password:
98 description: "Vous pouvez changer ici votre mot de passe. Le mot de passe doit contenir au moins 8 caractères." 115 description: "Vous pouvez changer ici votre mot de passe. Le mot de passe doit contenir au moins 8 caractères."
99 old_password_label: "Mot de passe actuel" 116 old_password_label: "Mot de passe actuel"
@@ -145,6 +162,7 @@ entry:
145 archived: "Articles lus" 162 archived: "Articles lus"
146 filtered: "Articles filtrés" 163 filtered: "Articles filtrés"
147 filtered_tags: "Articles filtrés par tags :" 164 filtered_tags: "Articles filtrés par tags :"
165 filtered_search: 'Articles filtrés par recherche :'
148 untagged: "Article sans tag" 166 untagged: "Article sans tag"
149 list: 167 list:
150 number_on_the_page: "{0} Il n’y a pas d’articles.|{1} Il y a un article.|]1,Inf[ Il y a %count% articles." 168 number_on_the_page: "{0} Il n’y a pas d’articles.|{1} Il y a un article.|]1,Inf[ Il y a %count% articles."
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: "A une photo" 186 preview_picture_label: "A une photo"
169 preview_picture_help: "Photo" 187 preview_picture_help: "Photo"
170 language_label: "Langue" 188 language_label: "Langue"
189 http_status_label: 'Statut HTTP'
171 reading_time: 190 reading_time:
172 label: "Durée de lecture en minutes" 191 label: "Durée de lecture en minutes"
173 from: "de" 192 from: "de"
@@ -209,6 +228,8 @@ entry:
209 placeholder: "http://website.com" 228 placeholder: "http://website.com"
210 form_new: 229 form_new:
211 url_label: "Adresse" 230 url_label: "Adresse"
231 search:
232 placeholder: "Que recherchez-vous ?"
212 edit: 233 edit:
213 page_title: "Éditer un article" 234 page_title: "Éditer un article"
214 title_label: "Titre" 235 title_label: "Titre"
@@ -251,6 +272,9 @@ about:
251 272
252howto: 273howto:
253 page_title: "Aide" 274 page_title: "Aide"
275 tab_menu:
276 add_link: "Ajouter un lien"
277 shortcuts: "Utiliser les raccourcis"
254 page_description: "Il y a plusieurs façon d’enregistrer un article :" 278 page_description: "Il y a plusieurs façon d’enregistrer un article :"
255 top_menu: 279 top_menu:
256 browser_addons: "Extensions de navigateur" 280 browser_addons: "Extensions de navigateur"
@@ -269,6 +293,33 @@ howto:
269 windows: "sur Microsoft Store" 293 windows: "sur Microsoft Store"
270 bookmarklet: 294 bookmarklet:
271 description: "Glissez et déposez ce lien dans votre barre de favoris :" 295 description: "Glissez et déposez ce lien dans votre barre de favoris :"
296 shortcuts:
297 page_description: Voici les raccourcis disponibles dans wallabag.
298 shortcut: Raccourci
299 action: Action
300 all_pages_title: Raccourcis disponibles dans toutes les pages
301 go_unread: Afficher les articles non lus
302 go_starred: Afficher les articles favoris
303 go_archive: Afficher les articles lus
304 go_all: Afficher tous les articles
305 go_tags: Afficher les tags
306 go_config: Aller à la configuration
307 go_import: Aller aux imports
308 go_developers: Aller à la section Développeurs
309 go_howto: Afficher l'aide (cette page !)
310 go_logout: Se déconnecter
311 list_title: Raccourcis disponibles dans les pages de liste
312 search: Afficher le formulaire de recherche
313 article_title: Raccourcis disponibles quand on affiche un article
314 open_original: Ouvrir l'URL originale de l'article
315 toggle_favorite: Changer le statut Favori de l'article
316 toggle_archive: Changer le status Lu de l'article
317 delete: Supprimer l'article
318 material_title: Raccourcis disponibles avec le thème Material uniquement
319 add_link: Ajouter un nouvel article
320 hide_form: Masquer le formulaire courant (recherche ou nouvel article)
321 arrows_navigation: Naviguer à travers les articles
322 open_article: Afficher l'article sélectionné
272 323
273quickstart: 324quickstart:
274 page_title: "Pour bien débuter" 325 page_title: "Pour bien débuter"
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 number_on_the_page: "{0} Il n’y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags." 381 number_on_the_page: "{0} Il n’y a pas de tag.|{1} Il y a un tag.|]1,Inf[ Il y a %count% tags."
331 see_untagged_entries: "Voir les articles sans tag" 382 see_untagged_entries: "Voir les articles sans tag"
383 new:
384 add: 'Ajouter'
385 placeholder: 'Vous pouvez ajouter plusieurs tags, séparés par une virgule.'
332 386
333import: 387import:
334 page_title: "Importer" 388 page_title: "Importer"
@@ -362,6 +416,7 @@ import:
362 how_to: "Choisissez le fichier de votre export Readability et cliquez sur le bouton ci-dessous pour l’importer." 416 how_to: "Choisissez le fichier de votre export Readability et cliquez sur le bouton ci-dessous pour l’importer."
363 worker: 417 worker:
364 enabled: "Les imports sont asynchrones. Une fois l’import commencé un worker externe traitera les messages un par un. Le service activé est :" 418 enabled: "Les imports sont asynchrones. Une fois l’import commencé un worker externe traitera les messages un par un. Le service activé est :"
419 download_images_warning: "Vous avez configuré le téléchagement des images pour vos articles. Combiné à l'import classique, cette opération peut être très très longue (voire échouer). Nous vous conseillons <strong>vivement</strong> d'activer les imports asynchrones."
365 firefox: 420 firefox:
366 page_title: "Import > Firefox" 421 page_title: "Import > Firefox"
367 description: "Cet outil va vous permettre d’importer tous vos marques-pages de Firefox. Ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde... ». Vous allez récupérer un fichier .json. </p>" 422 description: "Cet outil va vous permettre d’importer tous vos marques-pages de Firefox. Ouvrez le panneau des marques-pages (Ctrl+Maj+O), puis dans « Importation et sauvegarde », choisissez « Sauvegarde... ». Vous allez récupérer un fichier .json. </p>"
@@ -374,6 +429,10 @@ import:
374 page_title: "Import > Instapaper" 429 page_title: "Import > Instapaper"
375 description: "Sur la page des paramètres (https://www.instapaper.com/user), cliquez sur « Download .CSV file » dans la section « Export ». Un fichier CSV sera téléchargé (« instapaper-export.csv »)." 430 description: "Sur la page des paramètres (https://www.instapaper.com/user), cliquez sur « Download .CSV file » dans la section « Export ». Un fichier CSV sera téléchargé (« instapaper-export.csv »)."
376 how_to: "Choisissez le fichier de votre export Instapaper et cliquez sur le bouton ci-dessous pour l’importer." 431 how_to: "Choisissez le fichier de votre export Instapaper et cliquez sur le bouton ci-dessous pour l’importer."
432 pinboard:
433 page_title: "Import > Pinboard"
434 description: "Sur la page « Backup » (https://pinboard.in/settings/backup), cliquez sur « JSON » dans la section « Bookmarks ». Un fichier json (sans extension) sera téléchargé (« pinboard_export »)."
435 how_to: "Choisissez le fichier de votre export Pinboard et cliquez sur le bouton ci-dessous pour l’importer."
377 436
378developer: 437developer:
379 page_title: "Développeur" 438 page_title: "Développeur"
@@ -465,8 +524,10 @@ flashes:
465 rss_updated: "La configuration des flux RSS a bien été mise à jour" 524 rss_updated: "La configuration des flux RSS a bien été mise à jour"
466 tagging_rules_updated: "Règles mises à jour" 525 tagging_rules_updated: "Règles mises à jour"
467 tagging_rules_deleted: "Règle supprimée" 526 tagging_rules_deleted: "Règle supprimée"
468 user_added: "Utilisateur \"%username%\" ajouté"
469 rss_token_updated: "Jeton RSS mis à jour" 527 rss_token_updated: "Jeton RSS mis à jour"
528 annotations_reset: Annotations supprimées
529 tags_reset: Tags supprimés
530 entries_reset: Articles supprimés
470 entry: 531 entry:
471 notice: 532 notice:
472 entry_already_saved: "Article déjà sauvegardé le %date%" 533 entry_already_saved: "Article déjà sauvegardé le %date%"
@@ -496,3 +557,8 @@ flashes:
496 notice: 557 notice:
497 client_created: "Nouveau client %name% créé" 558 client_created: "Nouveau client %name% créé"
498 client_deleted: "Client %name% supprimé" 559 client_deleted: "Client %name% supprimé"
560 user:
561 notice:
562 added: 'Utilisateur "%username%" ajouté'
563 updated: 'Utilisateur "%username%" mis à jour'
564 deleted: 'Utilisateur "%username%" supprimé'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
index b7d066ab..d84f7dbf 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
@@ -70,7 +70,12 @@ config:
70 200_word: 'Leggo ~200 parole al minuto' 70 200_word: 'Leggo ~200 parole al minuto'
71 300_word: 'Leggo ~300 parole al minuto' 71 300_word: 'Leggo ~300 parole al minuto'
72 400_word: 'Leggo ~400 parole al minuto' 72 400_word: 'Leggo ~400 parole al minuto'
73 action_mark_as_read:
74 # label: 'Where do you to be redirected after mark an article as read?'
75 # redirect_homepage: 'To the homepage'
76 # redirect_current_page: 'To the current page'
73 pocket_consumer_key_label: Consumer key per Pocket per importare i contenuti 77 pocket_consumer_key_label: Consumer key per Pocket per importare i contenuti
78 # android_configuration: Configure your Android application
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 # help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 # help_items_per_page: "You can change the number of articles displayed on each page." 80 # help_items_per_page: "You can change the number of articles displayed on each page."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'E-mail' 99 email_label: 'E-mail'
95 twoFactorAuthentication_label: 'Two factor authentication' 100 twoFactorAuthentication_label: 'Two factor authentication'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 # title: Delete my account (a.k.a danger zone)
104 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
105 # confirm: Are you really sure? (THIS CAN'T BE UNDONE)
106 # button: Delete my account
107 reset:
108 # title: Reset area (a.k.a danger zone)
109 # description: By hiting buttons below you'll have ability to remove some informations from your account. Be aware that these actions are IRREVERSIBLE.
110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags
112 # entries: Remove ALL entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 # description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'Password corrente' 116 old_password_label: 'Password corrente'
@@ -145,6 +162,7 @@ entry:
145 archived: 'Contenuti archiviati' 162 archived: 'Contenuti archiviati'
146 filtered: 'Contenuti filtrati' 163 filtered: 'Contenuti filtrati'
147 # filtered_tags: 'Filtered by tags:' 164 # filtered_tags: 'Filtered by tags:'
165 # filtered_search: 'Filtered by search:'
148 # untagged: 'Untagged entries' 166 # untagged: 'Untagged entries'
149 list: 167 list:
150 number_on_the_page: "{0} Non ci sono contenuti.|{1} C'è un contenuto.|]1,Inf[ Ci sono %count% contenuti." 168 number_on_the_page: "{0} Non ci sono contenuti.|{1} C'è un contenuto.|]1,Inf[ Ci sono %count% contenuti."
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: "Ha un'immagine di anteprima" 186 preview_picture_label: "Ha un'immagine di anteprima"
169 preview_picture_help: 'Immagine di anteprima' 187 preview_picture_help: 'Immagine di anteprima'
170 language_label: 'Lingua' 188 language_label: 'Lingua'
189 # http_status_label: 'HTTP status'
171 reading_time: 190 reading_time:
172 label: 'Tempo di lettura in minuti' 191 label: 'Tempo di lettura in minuti'
173 from: 'da' 192 from: 'da'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
210 form_new: 229 form_new:
211 url_label: Url 230 url_label: Url
231 search:
232 # placeholder: 'What are you looking for?'
212 edit: 233 edit:
213 page_title: 'Modifica voce' 234 page_title: 'Modifica voce'
214 title_label: 'Titolo' 235 title_label: 'Titolo'
@@ -252,6 +273,9 @@ about:
252howto: 273howto:
253 page_title: 'How to' 274 page_title: 'How to'
254 page_description: 'Ci sono diversi modi per salvare un contenuto:' 275 page_description: 'Ci sono diversi modi per salvare un contenuto:'
276 tab_menu:
277 # add_link: "Add a link"
278 # shortcuts: "Use shortcuts"
255 top_menu: 279 top_menu:
256 browser_addons: 'tramite addons del Browser' 280 browser_addons: 'tramite addons del Browser'
257 mobile_apps: 'tramite app Mobile' 281 mobile_apps: 'tramite app Mobile'
@@ -269,6 +293,33 @@ howto:
269 windows: 'sullo store di Microsoft' 293 windows: 'sullo store di Microsoft'
270 bookmarklet: 294 bookmarklet:
271 description: 'Trascinando e rilasciando questo link sulla barra dei bookmark del tuo browser:' 295 description: 'Trascinando e rilasciando questo link sulla barra dei bookmark del tuo browser:'
296 shortcuts:
297 # page_description: Here are the shortcuts available in wallabag.
298 # shortcut: Shortcut
299 # action: Action
300 # all_pages_title: Shortcuts available in all pages
301 # go_unread: Go to unread
302 # go_starred: Go to starred
303 # go_archive: Go to archive
304 # go_all: Go to all entries
305 # go_tags: Go to tags
306 # go_config: Go to config
307 # go_import: Go to import
308 # go_developers: Go to developers
309 # go_howto: Go to howto (this page!)
310 # go_logout: Logout
311 # list_title: Shortcuts available in listing pages
312 # search: Display the search form
313 # article_title: Shortcuts available in entry view
314 # open_original: Open original URL of the entry
315 # toggle_favorite: Toggle star status for the entry
316 # toggle_archive: Toggle read status for the entry
317 # delete: Delete the entry
318 # material_title: Shortcuts available with Material theme only
319 # add_link: Add a new link
320 # hide_form: Hide the current form (search or new link)
321 # arrows_navigation: Navigate through articles
322 # open_article: Display the selected entry
272 323
273quickstart: 324quickstart:
274 page_title: 'Introduzione' 325 page_title: 'Introduzione'
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 number_on_the_page: "{0} Non ci sono tag.|{1} C'è un tag.|]1,Inf[ ci sono %count% tag." 381 number_on_the_page: "{0} Non ci sono tag.|{1} C'è un tag.|]1,Inf[ ci sono %count% tag."
331 # see_untagged_entries: 'See untagged entries' 382 # see_untagged_entries: 'See untagged entries'
383 new:
384 # add: 'Add'
385 # placeholder: 'You can add several tags, separated by a comma.'
332 386
333import: 387import:
334 page_title: 'Importa' 388 page_title: 'Importa'
@@ -362,6 +416,7 @@ import:
362 # how_to: 'Please select your Readability export and click on the below button to upload and import it.' 416 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
363 worker: 417 worker:
364 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" 418 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
419 # download_images_warning: "You enabled downloading images for your articles. Combined with classic import it can take ages to proceed (or maybe failed). We <strong>strongly recommend</strong> to enable asynchronous import to avoid errors."
365 firefox: 420 firefox:
366 page_title: 'Importa da > Firefox' 421 page_title: 'Importa da > Firefox'
367 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file." 422 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
@@ -374,6 +429,10 @@ import:
374 page_title: 'Importa da > Instapaper' 429 page_title: 'Importa da > Instapaper'
375 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").' 430 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
376 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.' 431 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
432 pinboard:
433 page_title: "Importa da > Pinboard"
434 # description: 'This importer will import all your Instapaper articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").'
435 # how_to: 'Please select your Pinboard export and click on the below button to upload and import it.'
377 436
378developer: 437developer:
379 page_title: 'Sviluppatori' 438 page_title: 'Sviluppatori'
@@ -465,8 +524,10 @@ flashes:
465 rss_updated: 'Informazioni RSS aggiornate' 524 rss_updated: 'Informazioni RSS aggiornate'
466 tagging_rules_updated: 'Regole di tagging aggiornate' 525 tagging_rules_updated: 'Regole di tagging aggiornate'
467 tagging_rules_deleted: 'Regola di tagging aggiornate' 526 tagging_rules_deleted: 'Regola di tagging aggiornate'
468 user_added: 'Utente "%username%" aggiunto'
469 rss_token_updated: 'RSS token aggiornato' 527 rss_token_updated: 'RSS token aggiornato'
528 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset
530 # entries_reset: Entries reset
470 entry: 531 entry:
471 notice: 532 notice:
472 entry_already_saved: 'Contenuto già salvato in data %date%' 533 entry_already_saved: 'Contenuto già salvato in data %date%'
@@ -496,3 +557,8 @@ flashes:
496 notice: 557 notice:
497 client_created: 'Nuovo client creato.' 558 client_created: 'Nuovo client creato.'
498 client_deleted: 'Client eliminato' 559 client_deleted: 'Client eliminato'
560 user:
561 notice:
562 # added: 'User "%username%" added'
563 # updated: 'User "%username%" updated'
564 # deleted: 'User "%username%" deleted'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
index 16ef1e5d..f2215a07 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
@@ -25,13 +25,13 @@ menu:
25 internal_settings: 'Configuracion interna' 25 internal_settings: 'Configuracion interna'
26 import: 'Importar' 26 import: 'Importar'
27 howto: 'Ajuda' 27 howto: 'Ajuda'
28 developer: 'Desvolopador' 28 developer: 'Desvolopaire'
29 logout: 'Desconnexion' 29 logout: 'Desconnexion'
30 about: 'A prepaus' 30 about: 'A prepaus'
31 search: 'Cercar' 31 search: 'Cercar'
32 save_link: 'Enregistrar un novèl article' 32 save_link: 'Enregistrar un novèl article'
33 back_to_unread: 'Tornar als articles pas legits' 33 back_to_unread: 'Tornar als articles pas legits'
34 # users_management: 'Users management' 34 users_management: 'Gestion dels utilizaires'
35 top: 35 top:
36 add_new_entry: 'Enregistrar un novèl article' 36 add_new_entry: 'Enregistrar un novèl article'
37 search: 'Cercar' 37 search: 'Cercar'
@@ -46,7 +46,7 @@ footer:
46 social: 'Social' 46 social: 'Social'
47 powered_by: 'propulsat per' 47 powered_by: 'propulsat per'
48 about: 'A prepaus' 48 about: 'A prepaus'
49 # stats: Since %user_creation% you read %nb_archives% articles. That is about %per_day% a day! 49 stats: "Dempuèi %user_creation% avètz legit %nb_archives% articles. Es a l'entorn de %per_day% per jorn !"
50 50
51config: 51config:
52 page_title: 'Configuracion' 52 page_title: 'Configuracion'
@@ -70,7 +70,12 @@ config:
70 200_word: "Legissi a l'entorn de 200 mots per minuta" 70 200_word: "Legissi a l'entorn de 200 mots per minuta"
71 300_word: "Legissi a l'entorn de 300 mots per minuta" 71 300_word: "Legissi a l'entorn de 300 mots per minuta"
72 400_word: "Legissi a l'entorn de 400 mots per minuta" 72 400_word: "Legissi a l'entorn de 400 mots per minuta"
73 action_mark_as_read:
74 # label: 'Where do you to be redirected after mark an article as read?'
75 # redirect_homepage: 'To the homepage'
76 # redirect_current_page: 'To the current page'
73 pocket_consumer_key_label: Clau d'autentificacion Pocket per importar las donadas 77 pocket_consumer_key_label: Clau d'autentificacion Pocket per importar las donadas
78 android_configuration: Configuratz vòstra aplicacion Android
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 # help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 # help_items_per_page: "You can change the number of articles displayed on each page." 80 # help_items_per_page: "You can change the number of articles displayed on each page."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'Adreça de corrièl' 99 email_label: 'Adreça de corrièl'
95 twoFactorAuthentication_label: 'Dobla autentificacion' 100 twoFactorAuthentication_label: 'Dobla autentificacion'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 title: Suprimir mon compte (Mèfi zòna perilhosa)
104 description: Se confirmatz la supression de vòstre compte, TOTES vòstres articles, TOTAS vòstras etiquetas, TOTAS vòstras anotacions e vòstre compte seràn suprimits per totjorn. E aquò es IRREVERSIBLE. Puèi seretz desconnectat.
105 confirm: Sètz vertadièrament segur ? (ES IRREVERSIBLE)
106 button: Suprimir mon compte
107 reset:
108 title: Zòna de reïnicializacion (Mèfi zòna perilhosa)
109 description: En clicant sul boton çai-jos auretz la possibilitat de levar qualques informacions de vòstre compte. Mèfi que totas aquelas accions son IRREVERSIBLAS.
110 annotations: Levar TOTAS las anotacions
111 tags: Levar TOTAS las etiquetas
112 entries: Levar TOTES los articles
113 confirm: Sètz vertadièrament segur ? (ES IRREVERSIBLE)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 # description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'Senhal actual' 116 old_password_label: 'Senhal actual'
@@ -103,7 +120,7 @@ config:
103 if_label: 'se' 120 if_label: 'se'
104 then_tag_as_label: 'alara atribuir las etiquetas' 121 then_tag_as_label: 'alara atribuir las etiquetas'
105 delete_rule_label: 'suprimir' 122 delete_rule_label: 'suprimir'
106 # edit_rule_label: 'edit' 123 edit_rule_label: 'modificar'
107 rule_label: 'Règla' 124 rule_label: 'Règla'
108 tags_label: 'Etiquetas' 125 tags_label: 'Etiquetas'
109 faq: 126 faq:
@@ -145,6 +162,7 @@ entry:
145 archived: 'Articles legits' 162 archived: 'Articles legits'
146 filtered: 'Articles filtrats' 163 filtered: 'Articles filtrats'
147 filtered_tags: 'Filtats per etiquetas:' 164 filtered_tags: 'Filtats per etiquetas:'
165 # filtered_search: 'Filtered by search:'
148 untagged: 'Articles sens etiqueta' 166 untagged: 'Articles sens etiqueta'
149 list: 167 list:
150 number_on_the_page: "{0} I a pas cap d'article.|{1} I a un article.|]1,Inf[ I a %count% articles." 168 number_on_the_page: "{0} I a pas cap d'article.|{1} I a un article.|]1,Inf[ I a %count% articles."
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: 'A una fotò' 186 preview_picture_label: 'A una fotò'
169 preview_picture_help: 'Fotò' 187 preview_picture_help: 'Fotò'
170 language_label: 'Lenga' 188 language_label: 'Lenga'
189 # http_status_label: 'HTTP status'
171 reading_time: 190 reading_time:
172 label: 'Durada de lectura en minutas' 191 label: 'Durada de lectura en minutas'
173 from: 'de' 192 from: 'de'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
210 form_new: 229 form_new:
211 url_label: Url 230 url_label: Url
231 search:
232 # placeholder: 'What are you looking for?'
212 edit: 233 edit:
213 page_title: 'Modificar un article' 234 page_title: 'Modificar un article'
214 title_label: 'Títol' 235 title_label: 'Títol'
@@ -216,7 +237,7 @@ entry:
216 is_public_label: 'Public' 237 is_public_label: 'Public'
217 save_label: 'Enregistrar' 238 save_label: 'Enregistrar'
218 public: 239 public:
219 # shared_by_wallabag: "This article has been shared by <a href='%wallabag_instance%'>wallabag</a>" 240 shared_by_wallabag: "Aqueste article es estat partejat per <a href='%wallabag_instance%'>wallabag</a>"
220 241
221about: 242about:
222 page_title: 'A prepaus' 243 page_title: 'A prepaus'
@@ -252,6 +273,9 @@ about:
252howto: 273howto:
253 page_title: 'Ajuda' 274 page_title: 'Ajuda'
254 page_description: "I a mai d'un biais d'enregistrar un article :" 275 page_description: "I a mai d'un biais d'enregistrar un article :"
276 tab_menu:
277 # add_link: "Add a link"
278 # shortcuts: "Use shortcuts"
255 top_menu: 279 top_menu:
256 browser_addons: 'Extensions de navigator' 280 browser_addons: 'Extensions de navigator'
257 mobile_apps: 'Aplicacions mobil' 281 mobile_apps: 'Aplicacions mobil'
@@ -269,17 +293,44 @@ howto:
269 windows: 'sus Microsoft Store' 293 windows: 'sus Microsoft Store'
270 bookmarklet: 294 bookmarklet:
271 description: 'Lisatz-depausatz aqueste ligam dins vòstra barra de favorits :' 295 description: 'Lisatz-depausatz aqueste ligam dins vòstra barra de favorits :'
296 shortcuts:
297 # page_description: Here are the shortcuts available in wallabag.
298 # shortcut: Shortcut
299 # action: Action
300 # all_pages_title: Shortcuts available in all pages
301 # go_unread: Go to unread
302 # go_starred: Go to starred
303 # go_archive: Go to archive
304 # go_all: Go to all entries
305 # go_tags: Go to tags
306 # go_config: Go to config
307 # go_import: Go to import
308 # go_developers: Go to developers
309 # go_howto: Go to howto (this page!)
310 # go_logout: Logout
311 # list_title: Shortcuts available in listing pages
312 # search: Display the search form
313 # article_title: Shortcuts available in entry view
314 # open_original: Open original URL of the entry
315 # toggle_favorite: Toggle star status for the entry
316 # toggle_archive: Toggle read status for the entry
317 # delete: Delete the entry
318 # material_title: Shortcuts available with Material theme only
319 # add_link: Add a new link
320 # hide_form: Hide the current form (search or new link)
321 # arrows_navigation: Navigate through articles
322 # open_article: Display the selected entry
272 323
273quickstart: 324quickstart:
274 page_title: 'Per ben començar' 325 page_title: 'Per ben començar'
275 # more: 'More…' 326 more: 'Mai…'
276 intro: 327 intro:
277 title: 'Benvenguda sus wallabag !' 328 title: 'Benvenguda sus wallabag !'
278 paragraph_1: "Anem vos guidar per far lo torn de la proprietat e vos presentar unas fonccionalitats que vos poirián interessar per vos apropriar aquesta aisina." 329 paragraph_1: "Anem vos guidar per far lo torn de la proprietat e vos presentar unas fonccionalitats que vos poirián interessar per vos apropriar aquesta aisina."
279 paragraph_2: 'Seguètz-nos ' 330 paragraph_2: 'Seguètz-nos '
280 configure: 331 configure:
281 title: "Configuratz l'aplicacio" 332 title: "Configuratz l'aplicacion"
282 # description: 'In order to have an application which suits you, have a look into the configuration of wallabag.' 333 description: "Per fin d'aver una aplicacion que vos va ben, anatz veire la configuracion de wallabag."
283 language: "Cambiatz la lenga e l'estil de l'aplicacion" 334 language: "Cambiatz la lenga e l'estil de l'aplicacion"
284 rss: 'Activatz los fluxes RSS' 335 rss: 'Activatz los fluxes RSS'
285 tagging_rules: 'Escrivètz de règlas per classar automaticament vòstres articles' 336 tagging_rules: 'Escrivètz de règlas per classar automaticament vòstres articles'
@@ -293,7 +344,7 @@ quickstart:
293 import: 'Configurar los impòrt' 344 import: 'Configurar los impòrt'
294 first_steps: 345 first_steps:
295 title: 'Primièrs passes' 346 title: 'Primièrs passes'
296 # description: "Now wallabag is well configured, it's time to archive the web. You can click on the top right sign + to add a link." 347 description: "Ara wallabag es ben configurat, es lo moment d'archivar lo web. Podètz clicar sul signe + a man drecha amont per ajustar un ligam."
297 new_article: 'Ajustatz vòstre primièr article' 348 new_article: 'Ajustatz vòstre primièr article'
298 unread_articles: 'E racaptatz-lo !' 349 unread_articles: 'E racaptatz-lo !'
299 migrate: 350 migrate:
@@ -305,14 +356,14 @@ quickstart:
305 readability: 'Migrar dempuèi Readability' 356 readability: 'Migrar dempuèi Readability'
306 instapaper: 'Migrar dempuèi Instapaper' 357 instapaper: 'Migrar dempuèi Instapaper'
307 developer: 358 developer:
308 title: 'Pels desvolopadors' 359 title: 'Pels desvolopaires'
309 # description: 'We also thought to the developers: Docker, API, translations, etc.' 360 description: 'Avèm tanben pensat als desvolopaires : Docker, API, traduccions, etc.'
310 create_application: 'Crear vòstra aplicacion tèrça' 361 create_application: 'Crear vòstra aplicacion tèrça'
311 # use_docker: 'Use Docker to install wallabag' 362 use_docker: 'Utilizar Docker per installar wallabag'
312 docs: 363 docs:
313 title: 'Documentacion complèta' 364 title: 'Documentacion complèta'
314 # description: "There are so much features in wallabag. Don't hesitate to read the manual to know them and to learn how to use them." 365 description: "I a un fum de fonccionalitats dins wallabag. Esitetz pas a legir lo manual per las conéisser e aprendre a las utilizar."
315 annotate: 'Anotatar vòstre article' 366 annotate: 'Anotar vòstre article'
316 export: 'Convertissètz vòstres articles en ePub o en PDF' 367 export: 'Convertissètz vòstres articles en ePub o en PDF'
317 search_filters: "Aprenètz a utilizar lo motor de recèrca e los filtres per retrobar l'article que vos interèssa" 368 search_filters: "Aprenètz a utilizar lo motor de recèrca e los filtres per retrobar l'article que vos interèssa"
318 fetching_errors: "Qué far se mon article es pas recuperat coma cal ?" 369 fetching_errors: "Qué far se mon article es pas recuperat coma cal ?"
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 number_on_the_page: "{0} I a pas cap d'etiquetas.|{1} I a una etiqueta.|]1,Inf[ I a %count% etiquetas." 381 number_on_the_page: "{0} I a pas cap d'etiquetas.|{1} I a una etiqueta.|]1,Inf[ I a %count% etiquetas."
331 see_untagged_entries: "Afichar las entradas sens pas cap d'etiquetas" 382 see_untagged_entries: "Afichar las entradas sens pas cap d'etiquetas"
383 new:
384 # add: 'Add'
385 # placeholder: 'You can add several tags, separated by a comma.'
332 386
333import: 387import:
334 page_title: 'Importar' 388 page_title: 'Importar'
@@ -362,6 +416,7 @@ import:
362 how_to: "Mercés de seleccionar vòstre Readability fichièr e de clicar sul boton dejós per lo telecargar e l'importar." 416 how_to: "Mercés de seleccionar vòstre Readability fichièr e de clicar sul boton dejós per lo telecargar e l'importar."
363 worker: 417 worker:
364 enabled: "L'importacion se fa de manièra asincròna. Un còp l'importacion lançada, una aisina externa s'ocuparà dels messatges un per un. Lo servici actual es : " 418 enabled: "L'importacion se fa de manièra asincròna. Un còp l'importacion lançada, una aisina externa s'ocuparà dels messatges un per un. Lo servici actual es : "
419 download_images_warning: "Avètz activat lo telecargament de los imatges de vòstres articles. Combinat amb l'importacion classica, aquò pòt tardar un long moment (o benlèu fracassar). <strong>Recomandem fòrtament</strong> l'activacion de l'importacion asincròna per evitar las errors."
365 firefox: 420 firefox:
366 page_title: 'Importar > Firefox' 421 page_title: 'Importar > Firefox'
367 description: "Aquesta aisina importarà totas vòstres favorits de Firefox. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file." 422 description: "Aquesta aisina importarà totas vòstres favorits de Firefox. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
@@ -374,6 +429,10 @@ import:
374 page_title: 'Importar > Instapaper' 429 page_title: 'Importar > Instapaper'
375 description: "Aquesta aisina importarà totas vòstres articles d'Instapaper. Sus la pagina de paramètres (https://www.instapaper.com/user), clicatz sus \"Download .CSV file\" dins la seccion \"Export\". Un fichièr CSV serà telecargat (aital \"instapaper-export.csv\")." 430 description: "Aquesta aisina importarà totas vòstres articles d'Instapaper. Sus la pagina de paramètres (https://www.instapaper.com/user), clicatz sus \"Download .CSV file\" dins la seccion \"Export\". Un fichièr CSV serà telecargat (aital \"instapaper-export.csv\")."
376 how_to: "Mercés de causir vòstre fichièr Instapaper e de clicar sul boton dejós per lo telecargar e l'importar" 431 how_to: "Mercés de causir vòstre fichièr Instapaper e de clicar sul boton dejós per lo telecargar e l'importar"
432 pinboard:
433 # page_title: "Import > Pinboard"
434 # description: 'This importer will import all your Instapaper articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").'
435 # how_to: 'Please select your Pinboard export and click on the below button to upload and import it.'
377 436
378developer: 437developer:
379 page_title: 'Desvolopaire' 438 page_title: 'Desvolopaire'
@@ -397,7 +456,7 @@ developer:
397 warn_message_2: "Se suprimissètz un client, totas las aplicacions que l'emplegan foncionaràn pas mai amb vòstre compte wallabag." 456 warn_message_2: "Se suprimissètz un client, totas las aplicacions que l'emplegan foncionaràn pas mai amb vòstre compte wallabag."
398 action: 'Suprimir aqueste client' 457 action: 'Suprimir aqueste client'
399 client: 458 client:
400 page_title: 'Desvlopador > Novèl client' 459 page_title: 'Desvolopaire > Novèl client'
401 page_description: "Anatz crear un novèl client. Mercés de cumplir l'url de redireccion cap a vòstra aplicacion." 460 page_description: "Anatz crear un novèl client. Mercés de cumplir l'url de redireccion cap a vòstra aplicacion."
402 form: 461 form:
403 name_label: "Nom del client" 462 name_label: "Nom del client"
@@ -405,7 +464,7 @@ developer:
405 save_label: 'Crear un novèl client' 464 save_label: 'Crear un novèl client'
406 action_back: 'Retorn' 465 action_back: 'Retorn'
407 client_parameter: 466 client_parameter:
408 page_title: 'Desvolopador > Los paramètres de vòstre client' 467 page_title: 'Desvolopaire > Los paramètres de vòstre client'
409 page_description: 'Vaquí los paramètres de vòstre client' 468 page_description: 'Vaquí los paramètres de vòstre client'
410 field_name: 'Nom del client' 469 field_name: 'Nom del client'
411 field_id: 'ID Client' 470 field_id: 'ID Client'
@@ -413,7 +472,7 @@ developer:
413 back: 'Retour' 472 back: 'Retour'
414 read_howto: 'Legir "cossí crear ma primièra aplicacion"' 473 read_howto: 'Legir "cossí crear ma primièra aplicacion"'
415 howto: 474 howto:
416 page_title: 'Desvolopador > Cossí crear ma primièra aplicacion' 475 page_title: 'Desvolopaire > Cossí crear ma primièra aplicacion'
417 description: 476 description:
418 paragraph_1: "Las comandas seguentas utilizan la <a href=\"https://github.com/jkbrzt/httpie\">bibliotèca HTTPie</a>. Asseguratz-vos que siasqueòu installadas abans de l'utilizar." 477 paragraph_1: "Las comandas seguentas utilizan la <a href=\"https://github.com/jkbrzt/httpie\">bibliotèca HTTPie</a>. Asseguratz-vos que siasqueòu installadas abans de l'utilizar."
419 paragraph_2: "Vos cal un geton per escambiar entre vòstra aplicacion e l'API de wallabar." 478 paragraph_2: "Vos cal un geton per escambiar entre vòstra aplicacion e l'API de wallabar."
@@ -426,34 +485,34 @@ developer:
426 back: 'Retorn' 485 back: 'Retorn'
427 486
428user: 487user:
429 # page_title: Users management 488 page_title: 'Gestion dels utilizaires'
430 # new_user: Create a new user 489 new_user: 'Crear un novèl utilizaire'
431 # edit_user: Edit an existing user 490 edit_user: 'Modificar un utilizaire existent'
432 # description: "Here you can manage all users (create, edit and delete)" 491 description: "Aquí podètz gerir totes los utilizaires (crear, modificar e suprimir)"
433 # list: 492 list:
434 # actions: Actions 493 actions: 'Accions'
435 # edit_action: Edit 494 edit_action: 'Modificar'
436 # yes: Yes 495 yes: 'Òc'
437 # no: No 496 no: 'Non'
438 # create_new_one: Create a new user 497 create_new_one: 'Crear un novèl utilizaire'
439 form: 498 form:
440 username_label: "Nom d'utilizaire" 499 username_label: "Nom d'utilizaire"
441 # name_label: 'Name' 500 name_label: 'Nom'
442 password_label: 'Senhal' 501 password_label: 'Senhal'
443 repeat_new_password_label: 'Confirmatz vòstre novèl senhal' 502 repeat_new_password_label: 'Confirmatz vòstre novèl senhal'
444 plain_password_label: 'Senhal en clar' 503 plain_password_label: 'Senhal en clar'
445 email_label: 'Adreça de corrièl' 504 email_label: 'Adreça de corrièl'
446 # enabled_label: 'Enabled' 505 enabled_label: 'Actiu'
447 # locked_label: 'Locked' 506 locked_label: 'Varrolhat'
448 # last_login_label: 'Last login' 507 last_login_label: 'Darrièra connexion'
449 # twofactor_label: Two factor authentication 508 twofactor_label: 'Autentificacion doble-factor'
450 # save: Save 509 save: 'Enregistrar'
451 # delete: Delete 510 delete: 'Suprimir'
452 # delete_confirm: Are you sure? 511 delete_confirm: 'Sètz segur ?'
453 # back_to_list: Back to list 512 back_to_list: 'Tornar a la lista'
454 513
455error: 514error:
456 # page_title: An error occurred 515 page_title: Una error s'es produsida
457 516
458flashes: 517flashes:
459 config: 518 config:
@@ -465,8 +524,10 @@ flashes:
465 rss_updated: 'La configuracion dels fluxes RSS es ben estada mesa a jorn' 524 rss_updated: 'La configuracion dels fluxes RSS es ben estada mesa a jorn'
466 tagging_rules_updated: 'Règlas misa a jorn' 525 tagging_rules_updated: 'Règlas misa a jorn'
467 tagging_rules_deleted: 'Règla suprimida' 526 tagging_rules_deleted: 'Règla suprimida'
468 user_added: 'Utilizaire "%username%" apondut'
469 rss_token_updated: 'Geton RSS mes a jorn' 527 rss_token_updated: 'Geton RSS mes a jorn'
528 annotations_reset: Anotacions levadas
529 tags_reset: Etiquetas levadas
530 entries_reset: Articles levats
470 entry: 531 entry:
471 notice: 532 notice:
472 entry_already_saved: 'Article ja salvargardat lo %date%' 533 entry_already_saved: 'Article ja salvargardat lo %date%'
@@ -477,12 +538,12 @@ flashes:
477 entry_reloaded_failed: "L'article es estat cargat de nòu mai la recuperacion del contengut a fracassat" 538 entry_reloaded_failed: "L'article es estat cargat de nòu mai la recuperacion del contengut a fracassat"
478 entry_archived: 'Article marcat coma legit' 539 entry_archived: 'Article marcat coma legit'
479 entry_unarchived: 'Article marcat coma pas legit' 540 entry_unarchived: 'Article marcat coma pas legit'
480 entry_starred: 'Article apondut dins los favorits' 541 entry_starred: 'Article ajustat dins los favorits'
481 entry_unstarred: 'Article quitat dels favorits' 542 entry_unstarred: 'Article quitat dels favorits'
482 entry_deleted: 'Article suprimit' 543 entry_deleted: 'Article suprimit'
483 tag: 544 tag:
484 notice: 545 notice:
485 tag_added: 'Etiqueta aponduda' 546 tag_added: 'Etiqueta ajustada'
486 import: 547 import:
487 notice: 548 notice:
488 failed: "L'importacion a fracassat, mercés de tornar ensajar" 549 failed: "L'importacion a fracassat, mercés de tornar ensajar"
@@ -496,3 +557,8 @@ flashes:
496 notice: 557 notice:
497 client_created: 'Novèl client creat' 558 client_created: 'Novèl client creat'
498 client_deleted: 'Client suprimit' 559 client_deleted: 'Client suprimit'
560 user:
561 notice:
562 added: 'Utilizaire "%username%" ajustat'
563 updated: 'Utilizaire "%username%" mes a jorn'
564 deleted: 'Utilizaire "%username%" suprimit'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
index 73250cc0..9e6d3565 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
@@ -61,7 +61,7 @@ config:
61 save: 'Zapisz' 61 save: 'Zapisz'
62 form_settings: 62 form_settings:
63 theme_label: 'Temat' 63 theme_label: 'Temat'
64 items_per_page_label: 'Ilość elementóœ na stronie' 64 items_per_page_label: 'Ilość elementów na stronie'
65 language_label: 'Język' 65 language_label: 'Język'
66 reading_speed: 66 reading_speed:
67 label: 'Prędkość czytania' 67 label: 'Prędkość czytania'
@@ -70,12 +70,17 @@ config:
70 200_word: 'Czytam ~200 słów na minutę' 70 200_word: 'Czytam ~200 słów na minutę'
71 300_word: 'Czytam ~300 słów na minutę' 71 300_word: 'Czytam ~300 słów na minutę'
72 400_word: 'Czytam ~400 słów na minutę' 72 400_word: 'Czytam ~400 słów na minutę'
73 action_mark_as_read:
74 label: 'Gdzie zostaniesz przekierowany po oznaczeniu artukuły jako przeczytanego'
75 redirect_homepage: 'do strony głównej'
76 redirect_current_page: 'do bieżącej strony'
73 pocket_consumer_key_label: 'Klucz klienta Pocket do importu zawartości' 77 pocket_consumer_key_label: 'Klucz klienta Pocket do importu zawartości'
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 78 android_configuration: Skonfiguruj swoją androidową aplikację
75 # help_items_per_page: "You can change the number of articles displayed on each page." 79 help_theme: "Dopasuj wallabag do swoich potrzeb. Tutaj możesz wybrać preferowany przez ciebie motyw."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 80 help_items_per_page: "Możesz zmienić ilość artykułów wyświetlanych na każdej stronie."
77 # help_language: "You can change the language of wallabag interface." 81 help_reading_speed: "wallabag oblicza czas czytania każdego artykułu. Dzięki tej liście możesz określić swoje tempo. Wallabag przeliczy ponownie czas potrzebny, na przeczytanie każdego z artykułów."
78 # help_pocket_consumer_key: "Required for Pocket import. You can create it in your Pocket account." 82 help_language: "Możesz zmienić język interfejsu wallabag."
83 help_pocket_consumer_key: "Wymagane dla importu z Pocket. Możesz go stworzyć na swoim koncie Pocket."
79 form_rss: 84 form_rss:
80 description: 'Kanały RSS prowadzone przez wallabag pozwalają Ci na czytanie twoich zapisanych artykułów w twoium ulubionym czytniku RSS. Musisz najpierw wynegenerować tokena.‌' 85 description: 'Kanały RSS prowadzone przez wallabag pozwalają Ci na czytanie twoich zapisanych artykułów w twoium ulubionym czytniku RSS. Musisz najpierw wynegenerować tokena.‌'
81 token_label: 'Token RSS' 86 token_label: 'Token RSS'
@@ -93,9 +98,21 @@ config:
93 name_label: 'Nazwa' 98 name_label: 'Nazwa'
94 email_label: 'Adres email' 99 email_label: 'Adres email'
95 twoFactorAuthentication_label: 'Autoryzacja dwuetapowa' 100 twoFactorAuthentication_label: 'Autoryzacja dwuetapowa'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 help_twoFactorAuthentication: "Jeżeli włączysz autoryzację dwuetapową. Za każdym razem, kiedy będziesz chciał się zalogować, dostaniesz kod na swój e-mail."
102 delete:
103 title: Usuń moje konto (niebezpieczna strefa !)
104 description: Jeżeli usuniesz swoje konto, wszystkie twoje artykuły, tagi, adnotacje, oraz konto zostaną trwale usunięte (operacja jest NIEODWRACALNA). Następnie zostaniesz wylogowany.
105 confirm: Jesteś pewien? (tej operacji NIE MOŻNA cofnąć)
106 button: Usuń moje konto
107 reset:
108 title: Reset (niebezpieczna strefa)
109 description: Poniższe przyciski pozwalają usunąć pewne informacje z twojego konta. Uważaj te operacje są NIEODWRACALNE.
110 annotations: Usuń WSZYSTKIE adnotacje
111 tags: Usuń WSZYSTKIE tagi
112 entries: usuń WSZYTSTKIE wpisy
113 confirm: Jesteś pewien? (tej operacji NIE MOŻNA cofnąć)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 description: "Tutaj możesz zmienić swoje hasło. Twoje nowe hasło powinno mieć conajmniej 8 znaków."
99 old_password_label: 'Stare hasło' 116 old_password_label: 'Stare hasło'
100 new_password_label: 'Nowe hasło' 117 new_password_label: 'Nowe hasło'
101 repeat_new_password_label: 'Powtórz nowe hasło' 118 repeat_new_password_label: 'Powtórz nowe hasło'
@@ -145,6 +162,7 @@ entry:
145 archived: 'Zarchiwizowane wpisy' 162 archived: 'Zarchiwizowane wpisy'
146 filtered: 'Odfiltrowane wpisy' 163 filtered: 'Odfiltrowane wpisy'
147 filtered_tags: 'Filtrowane po tagach:' 164 filtered_tags: 'Filtrowane po tagach:'
165 filtered_search: 'Filtrowanie po wyszukiwaniu:'
148 untagged: 'Odtaguj wpisy' 166 untagged: 'Odtaguj wpisy'
149 list: 167 list:
150 number_on_the_page: '{0} Nie ma wpisów.|{1} Jest jeden wpis.|]1,Inf[ Są %count% wpisy.' 168 number_on_the_page: '{0} Nie ma wpisów.|{1} Jest jeden wpis.|]1,Inf[ Są %count% wpisy.'
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: 'Posiada podgląd obrazu' 186 preview_picture_label: 'Posiada podgląd obrazu'
169 preview_picture_help: 'Podgląd obrazu' 187 preview_picture_help: 'Podgląd obrazu'
170 language_label: 'Język' 188 language_label: 'Język'
189 http_status_label: 'Status HTTP'
171 reading_time: 190 reading_time:
172 label: 'Czas czytania w minutach' 191 label: 'Czas czytania w minutach'
173 from: 'od' 192 from: 'od'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
210 form_new: 229 form_new:
211 url_label: Url 230 url_label: Url
231 search:
232 placeholder: 'Czego szukasz?'
212 edit: 233 edit:
213 page_title: 'Edytuj wpis' 234 page_title: 'Edytuj wpis'
214 title_label: 'Tytuł' 235 title_label: 'Tytuł'
@@ -252,6 +273,9 @@ about:
252howto: 273howto:
253 page_title: 'Howto' 274 page_title: 'Howto'
254 page_description: 'Sposoby zapisania artykułu:' 275 page_description: 'Sposoby zapisania artykułu:'
276 tab_menu:
277 add_link: "Dodaj link"
278 shortcuts: "Użyj skrótów"
255 top_menu: 279 top_menu:
256 browser_addons: 'Wtyczki dla przeglądarki' 280 browser_addons: 'Wtyczki dla przeglądarki'
257 mobile_apps: 'Aplikacje mobilne' 281 mobile_apps: 'Aplikacje mobilne'
@@ -269,6 +293,33 @@ howto:
269 windows: 'w Microsoft Store' 293 windows: 'w Microsoft Store'
270 bookmarklet: 294 bookmarklet:
271 description: 'Przeciągnij i upuść ten link na swój pasek zakładek' 295 description: 'Przeciągnij i upuść ten link na swój pasek zakładek'
296 shortcuts:
297 page_description: Tutaj znajdują się skróty dostępne w wallabag.
298 shortcut: Skrót
299 action: Akcja
300 all_pages_title: Skróty dostępne na wszystkich stronach
301 go_unread: Idź do nieprzeczytanych
302 go_starred: Idź do oznaczonych gwiazdką
303 go_archive: Idź do archiwum
304 go_all: Idź do wszystkich wpisów
305 go_tags: Idź do tagów
306 go_config: Idź do konfiguracji
307 go_import: Idź do importu
308 go_developers: Idź do deweloperów
309 go_howto: Idź do howto (tej strony!)
310 go_logout: Wyloguj
311 list_title: Skróty dostępne w spisie stron
312 search: Pokaż formularz wyszukiwania
313 article_title: Skróty dostępne w widoku artykułu
314 open_original: Otwórz oryginalny adres URL wpisu
315 toggle_favorite: Oznacz wpis gwiazdką
316 toggle_archive: Oznacz wpis jako przeczytany
317 delete: Usuń wpis
318 material_title: Skróty dostępne wyłącznie w motywie Material
319 add_link: Dodaj nowy link
320 hide_form: Ukryj obecny formularz (wyszukiwania lub nowego linku)
321 arrows_navigation: Nawiguj pomiędzy artykułami
322 open_article: Wyświetl zaznaczony wpis
272 323
273quickstart: 324quickstart:
274 page_title: 'Szybki start' 325 page_title: 'Szybki start'
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 number_on_the_page: '{0} Nie ma tagów.|{1} Jest jeden tag.|]1,Inf[ Są %count% tagi.' 381 number_on_the_page: '{0} Nie ma tagów.|{1} Jest jeden tag.|]1,Inf[ Są %count% tagi.'
331 see_untagged_entries: 'Zobacz nieotagowane wpisy' 382 see_untagged_entries: 'Zobacz nieotagowane wpisy'
383 new:
384 add: 'Dodaj'
385 placeholder: 'Możesz dodać kilka tagów, oddzielając je przecinkami.'
332 386
333import: 387import:
334 page_title: 'Import' 388 page_title: 'Import'
@@ -362,6 +416,7 @@ import:
362 how_to: 'Wybierz swój plik eksportu z Readability i kliknij poniższy przycisk, aby go załadować.' 416 how_to: 'Wybierz swój plik eksportu z Readability i kliknij poniższy przycisk, aby go załadować.'
363 worker: 417 worker:
364 enabled: "Import jest wykonywany asynchronicznie. Od momentu rozpoczęcia importu, zewnętrzna usługa może zajmować się na raz tylko jednym zadaniem. Bieżącą usługą jest:" 418 enabled: "Import jest wykonywany asynchronicznie. Od momentu rozpoczęcia importu, zewnętrzna usługa może zajmować się na raz tylko jednym zadaniem. Bieżącą usługą jest:"
419 download_images_warning: "Włączyłeś pobieranie obrazów dla swoich artykułów. W połączeniu z klasycznym importem, może to zająć dużo czasu (lub zakończyć się niepowodzeniem).<strong>Zdecydowanie zalecamy</strong> włączenie asynchronicznego importu, w celu uniknięcia błędów."
365 firefox: 420 firefox:
366 page_title: 'Import > Firefox' 421 page_title: 'Import > Firefox'
367 description: "Ten importer zaimportuje wszystkie twoje zakładki z Firefoksa. Idź do twoich zakładek (Ctrl+Shift+O), następnie w \"Import i kopie zapasowe\", wybierz \"Utwórz kopię zapasową...\". Uzyskasz plik .json." 422 description: "Ten importer zaimportuje wszystkie twoje zakładki z Firefoksa. Idź do twoich zakładek (Ctrl+Shift+O), następnie w \"Import i kopie zapasowe\", wybierz \"Utwórz kopię zapasową...\". Uzyskasz plik .json."
@@ -374,6 +429,10 @@ import:
374 page_title: 'Import > Instapaper' 429 page_title: 'Import > Instapaper'
375 description: 'Ten importer, zaimportuje wszystkie twoje artykuły z Instapaper. W ustawieniach (https://www.instapaper.com/user), kliknij na "Download .CSV file" w sekcji "Export". Otrzymasz plik CSV.' 430 description: 'Ten importer, zaimportuje wszystkie twoje artykuły z Instapaper. W ustawieniach (https://www.instapaper.com/user), kliknij na "Download .CSV file" w sekcji "Export". Otrzymasz plik CSV.'
376 how_to: 'Wybierz swój plik eksportu z Instapaper i kliknij poniższy przycisk, aby go załadować.' 431 how_to: 'Wybierz swój plik eksportu z Instapaper i kliknij poniższy przycisk, aby go załadować.'
432 pinboard:
433 page_title: "Import > Pinboard"
434 description: 'Ten importer, zaimportuje wszystkie twoje artykuły z Pinboard. W ustawieniach kopii zapasowej (https://pinboard.in/settings/backup), kliknij na "JSON" w sekcji "Bookmarks". Otrzymasz plik "pinboard_export".'
435 how_to: 'Wybierz swój plik eksportu z Pinboard i kliknij poniższy przycisk, aby go załadować.'
377 436
378developer: 437developer:
379 page_title: 'Deweloper' 438 page_title: 'Deweloper'
@@ -453,7 +512,7 @@ user:
453 back_to_list: Powrót do listy 512 back_to_list: Powrót do listy
454 513
455error: 514error:
456 # page_title: An error occurred 515 page_title: Wystąpił błąd
457 516
458flashes: 517flashes:
459 config: 518 config:
@@ -465,8 +524,10 @@ flashes:
465 rss_updated: 'Informacje RSS zaktualizowane' 524 rss_updated: 'Informacje RSS zaktualizowane'
466 tagging_rules_updated: 'Reguły tagowania zaktualizowane' 525 tagging_rules_updated: 'Reguły tagowania zaktualizowane'
467 tagging_rules_deleted: 'Reguła tagowania usunięta' 526 tagging_rules_deleted: 'Reguła tagowania usunięta'
468 user_added: 'Użytkownik "%username%" dodany'
469 rss_token_updated: 'Token kanału RSS zaktualizowany' 527 rss_token_updated: 'Token kanału RSS zaktualizowany'
528 annotations_reset: Zresetuj adnotacje
529 tags_reset: Zresetuj tagi
530 entries_reset: Zresetuj wpisy
470 entry: 531 entry:
471 notice: 532 notice:
472 entry_already_saved: 'Wpis już został dodany %date%' 533 entry_already_saved: 'Wpis już został dodany %date%'
@@ -496,3 +557,8 @@ flashes:
496 notice: 557 notice:
497 client_created: 'Nowy klient utworzony.' 558 client_created: 'Nowy klient utworzony.'
498 client_deleted: 'Klient usunięty' 559 client_deleted: 'Klient usunięty'
560 user:
561 notice:
562 added: 'Użytkownik "%username%" dodany'
563 updated: 'Użytkownik "%username%" zaktualizowany'
564 deleted: 'Użytkownik "%username%" usunięty'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
index a375ac7b..3dd6e7d8 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
@@ -70,7 +70,12 @@ config:
70 200_word: 'Posso ler ~200 palavras por minuto' 70 200_word: 'Posso ler ~200 palavras por minuto'
71 300_word: 'Posso ler ~300 palavras por minuto' 71 300_word: 'Posso ler ~300 palavras por minuto'
72 400_word: 'Posso ler ~400 palavras por minuto' 72 400_word: 'Posso ler ~400 palavras por minuto'
73 action_mark_as_read:
74 # label: 'Where do you to be redirected after mark an article as read?'
75 # redirect_homepage: 'To the homepage'
76 # redirect_current_page: 'To the current page'
73 pocket_consumer_key_label: 'Chave do consumidor do Pocket para importar conteúdo' 77 pocket_consumer_key_label: 'Chave do consumidor do Pocket para importar conteúdo'
78 # android_configuration: Configure your Android application
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 # help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 # help_items_per_page: "You can change the number of articles displayed on each page." 80 # help_items_per_page: "You can change the number of articles displayed on each page."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'E-mail' 99 email_label: 'E-mail'
95 twoFactorAuthentication_label: 'Autenticação de dois passos' 100 twoFactorAuthentication_label: 'Autenticação de dois passos'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 # title: Delete my account (a.k.a danger zone)
104 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
105 # confirm: Are you really sure? (THIS CAN'T BE UNDONE)
106 # button: Delete my account
107 reset:
108 # title: Reset area (a.k.a danger zone)
109 # description: By hiting buttons below you'll have ability to remove some informations from your account. Be aware that these actions are IRREVERSIBLE.
110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags
112 # entries: Remove ALL entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 # description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'Senha atual' 116 old_password_label: 'Senha atual'
@@ -145,6 +162,7 @@ entry:
145 archived: 'Entradas arquivadas' 162 archived: 'Entradas arquivadas'
146 filtered: 'Entradas filtradas' 163 filtered: 'Entradas filtradas'
147 filtered_tags: 'Filtrar por tags:' 164 filtered_tags: 'Filtrar por tags:'
165 # filtered_search: 'Filtered by search:'
148 untagged: 'Entradas sem tags' 166 untagged: 'Entradas sem tags'
149 list: 167 list:
150 number_on_the_page: '{0} Não existem entradas.|{1} Existe uma entrada.|]1,Inf[ Existem %count% entradas.' 168 number_on_the_page: '{0} Não existem entradas.|{1} Existe uma entrada.|]1,Inf[ Existem %count% entradas.'
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: 'Possui uma imagem de preview' 186 preview_picture_label: 'Possui uma imagem de preview'
169 preview_picture_help: 'Imagem de preview' 187 preview_picture_help: 'Imagem de preview'
170 language_label: 'Idioma' 188 language_label: 'Idioma'
189 # http_status_label: 'HTTP status'
171 reading_time: 190 reading_time:
172 label: 'Tempo de leitura em minutos' 191 label: 'Tempo de leitura em minutos'
173 from: 'de' 192 from: 'de'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
210 form_new: 229 form_new:
211 url_label: Url 230 url_label: Url
231 search:
232 # placeholder: 'What are you looking for?'
212 edit: 233 edit:
213 page_title: 'Editar uma entrada' 234 page_title: 'Editar uma entrada'
214 title_label: 'Título' 235 title_label: 'Título'
@@ -252,6 +273,9 @@ about:
252howto: 273howto:
253 page_title: 'How to' 274 page_title: 'How to'
254 page_description: 'Existem diferentes formas de salvar um artigo:' 275 page_description: 'Existem diferentes formas de salvar um artigo:'
276 tab_menu:
277 # add_link: "Add a link"
278 # shortcuts: "Use shortcuts"
255 top_menu: 279 top_menu:
256 browser_addons: 'Extensões de navegadores' 280 browser_addons: 'Extensões de navegadores'
257 mobile_apps: "App's móveis" 281 mobile_apps: "App's móveis"
@@ -269,6 +293,33 @@ howto:
269 windows: 'na Microsoft Store' 293 windows: 'na Microsoft Store'
270 bookmarklet: 294 bookmarklet:
271 description: 'Arraste e solve este link na sua barra de favoritos:' 295 description: 'Arraste e solve este link na sua barra de favoritos:'
296 shortcuts:
297 # page_description: Here are the shortcuts available in wallabag.
298 # shortcut: Shortcut
299 # action: Action
300 # all_pages_title: Shortcuts available in all pages
301 # go_unread: Go to unread
302 # go_starred: Go to starred
303 # go_archive: Go to archive
304 # go_all: Go to all entries
305 # go_tags: Go to tags
306 # go_config: Go to config
307 # go_import: Go to import
308 # go_developers: Go to developers
309 # go_howto: Go to howto (this page!)
310 # go_logout: Logout
311 # list_title: Shortcuts available in listing pages
312 # search: Display the search form
313 # article_title: Shortcuts available in entry view
314 # open_original: Open original URL of the entry
315 # toggle_favorite: Toggle star status for the entry
316 # toggle_archive: Toggle read status for the entry
317 # delete: Delete the entry
318 # material_title: Shortcuts available with Material theme only
319 # add_link: Add a new link
320 # hide_form: Hide the current form (search or new link)
321 # arrows_navigation: Navigate through articles
322 # open_article: Display the selected entry
272 323
273quickstart: 324quickstart:
274 page_title: 'Começo Rápido' 325 page_title: 'Começo Rápido'
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 number_on_the_page: '{0} Não existem tags.|{1} Uma tag.|]1,Inf[ Existem %count% tags.' 381 number_on_the_page: '{0} Não existem tags.|{1} Uma tag.|]1,Inf[ Existem %count% tags.'
331 see_untagged_entries: 'Ver entradas sem tags' 382 see_untagged_entries: 'Ver entradas sem tags'
383 new:
384 # add: 'Add'
385 # placeholder: 'You can add several tags, separated by a comma.'
332 386
333import: 387import:
334 page_title: 'Importar' 388 page_title: 'Importar'
@@ -362,6 +416,7 @@ import:
362 how_to: 'Por favor, selecione sua exportação do Readability e clique no botão abaixo para importá-la.' 416 how_to: 'Por favor, selecione sua exportação do Readability e clique no botão abaixo para importá-la.'
363 worker: 417 worker:
364 enabled: "A importação é feita assíncronamente. Uma vez que a tarefa de importação é iniciada, um trabalho externo pode executar tarefas uma por vez. O serviço atual é:" 418 enabled: "A importação é feita assíncronamente. Uma vez que a tarefa de importação é iniciada, um trabalho externo pode executar tarefas uma por vez. O serviço atual é:"
419 # download_images_warning: "You enabled downloading images for your articles. Combined with classic import it can take ages to proceed (or maybe failed). We <strong>strongly recommend</strong> to enable asynchronous import to avoid errors."
365 firefox: 420 firefox:
366 page_title: 'Importar > Firefox' 421 page_title: 'Importar > Firefox'
367 description: "Com este importador você importa todos os favoritos de seu Firefox. Somente vá até seus favoritos (Ctrl+Maj+O), e em \"Importar e Backup\" e escolha \"Backup...\". Você terá então um arquivo .json." 422 description: "Com este importador você importa todos os favoritos de seu Firefox. Somente vá até seus favoritos (Ctrl+Maj+O), e em \"Importar e Backup\" e escolha \"Backup...\". Você terá então um arquivo .json."
@@ -374,6 +429,10 @@ import:
374 page_title: 'Importar > Instapaper' 429 page_title: 'Importar > Instapaper'
375 description: 'Este importador pode importar todos os artigos do seu Instapaper. Nas página de configurações (https://www.instapaper.com/user), clique em "Download .CSV file" na seção "Export". Um arquivo CSV será baixado (algo como "instapaper-export.csv").' 430 description: 'Este importador pode importar todos os artigos do seu Instapaper. Nas página de configurações (https://www.instapaper.com/user), clique em "Download .CSV file" na seção "Export". Um arquivo CSV será baixado (algo como "instapaper-export.csv").'
376 how_to: 'Por favor, selecione sua exportação do seu Instapaper e clique no botão abaixo para importá-la.' 431 how_to: 'Por favor, selecione sua exportação do seu Instapaper e clique no botão abaixo para importá-la.'
432 pinboard:
433 # page_title: "Import > Pinboard"
434 # description: 'This importer will import all your Instapaper articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").'
435 # how_to: 'Please select your Pinboard export and click on the below button to upload and import it.'
377 436
378developer: 437developer:
379 page_title: 'Desenvolvedor' 438 page_title: 'Desenvolvedor'
@@ -452,17 +511,23 @@ user:
452 delete_confirm: 'Tem certeza?' 511 delete_confirm: 'Tem certeza?'
453 back_to_list: 'Voltar para a lista' 512 back_to_list: 'Voltar para a lista'
454 513
514error:
515 # page_title: An error occurred
516
455flashes: 517flashes:
456 config: 518 config:
457 notice: 519 notice:
458 config_saved: 'Configiração salva.' 520 config_saved: 'Configiração salva.'
459 password_updated: 'Senha atualizada' 521 password_updated: 'Senha atualizada'
460 password_not_updated_demo: 'Em modo de demonstração, você não pode alterar a senha deste usuário.' 522 password_not_updated_demo: 'Em modo de demonstração, você não pode alterar a senha deste usuário.'
461 user_updated: 'Informação atualizada' 523 # user_updated: 'Information updated'
462 rss_updated: 'Informação de RSS atualizada' 524 rss_updated: 'Informação de RSS atualizada'
463 tagging_rules_updated: 'Regras de tags atualizadas' 525 tagging_rules_updated: 'Regras de tags atualizadas'
464 tagging_rules_deleted: 'Regra de tag apagada' 526 tagging_rules_deleted: 'Regra de tag apagada'
465 rss_token_updated: 'Token RSS atualizado' 527 rss_token_updated: 'Token RSS atualizado'
528 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset
530 # entries_reset: Entries reset
466 entry: 531 entry:
467 notice: 532 notice:
468 entry_already_saved: 'Entrada já foi salva em %date%' 533 entry_already_saved: 'Entrada já foi salva em %date%'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
index 7d8fcea3..0386c0b6 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
@@ -70,7 +70,12 @@ config:
70 # 200_word: 'I read ~200 words per minute' 70 # 200_word: 'I read ~200 words per minute'
71 # 300_word: 'I read ~300 words per minute' 71 # 300_word: 'I read ~300 words per minute'
72 # 400_word: 'I read ~400 words per minute' 72 # 400_word: 'I read ~400 words per minute'
73 action_mark_as_read:
74 # label: 'Where do you to be redirected after mark an article as read?'
75 # redirect_homepage: 'To the homepage'
76 # redirect_current_page: 'To the current page'
73 pocket_consumer_key_label: Cheie consumator pentru importarea contentului din Pocket 77 pocket_consumer_key_label: Cheie consumator pentru importarea contentului din Pocket
78 # android_configuration: Configure your Android application
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 # help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 # help_items_per_page: "You can change the number of articles displayed on each page." 80 # help_items_per_page: "You can change the number of articles displayed on each page."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'E-mail' 99 email_label: 'E-mail'
95 # twoFactorAuthentication_label: 'Two factor authentication' 100 # twoFactorAuthentication_label: 'Two factor authentication'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 # title: Delete my account (a.k.a danger zone)
104 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
105 # confirm: Are you really sure? (THIS CAN'T BE UNDONE)
106 # button: Delete my account
107 reset:
108 # title: Reset area (a.k.a danger zone)
109 # description: By hiting buttons below you'll have ability to remove some informations from your account. Be aware that these actions are IRREVERSIBLE.
110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags
112 # entries: Remove ALL entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 # description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'Parola veche' 116 old_password_label: 'Parola veche'
@@ -145,6 +162,7 @@ entry:
145 # archived: 'Archived entries' 162 # archived: 'Archived entries'
146 # filtered: 'Filtered entries' 163 # filtered: 'Filtered entries'
147 # filtered_tags: 'Filtered by tags:' 164 # filtered_tags: 'Filtered by tags:'
165 # filtered_search: 'Filtered by search:'
148 # untagged: 'Untagged entries' 166 # untagged: 'Untagged entries'
149 list: 167 list:
150 # number_on_the_page: '{0} There is no entry.|{1} There is one entry.|]1,Inf[ There are %count% entries.' 168 # number_on_the_page: '{0} There is no entry.|{1} There is one entry.|]1,Inf[ There are %count% entries.'
@@ -168,6 +186,7 @@ entry:
168 preview_picture_label: 'Are o imagine de previzualizare' 186 preview_picture_label: 'Are o imagine de previzualizare'
169 preview_picture_help: 'Previzualizare imagine' 187 preview_picture_help: 'Previzualizare imagine'
170 language_label: 'Limbă' 188 language_label: 'Limbă'
189 # http_status_label: 'HTTP status'
171 reading_time: 190 reading_time:
172 label: 'Timp de citire în minute' 191 label: 'Timp de citire în minute'
173 from: 'de la' 192 from: 'de la'
@@ -209,6 +228,8 @@ entry:
209 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
210 form_new: 229 form_new:
211 url_label: Url 230 url_label: Url
231 search:
232 # placeholder: 'What are you looking for?'
212 edit: 233 edit:
213 # page_title: 'Edit an entry' 234 # page_title: 'Edit an entry'
214 # title_label: 'Title' 235 # title_label: 'Title'
@@ -252,6 +273,9 @@ about:
252howto: 273howto:
253 page_title: 'Cum să' 274 page_title: 'Cum să'
254 # page_description: 'There are several ways to save an article:' 275 # page_description: 'There are several ways to save an article:'
276 tab_menu:
277 # add_link: "Add a link"
278 # shortcuts: "Use shortcuts"
255 top_menu: 279 top_menu:
256 browser_addons: 'Add-On-uri de Browser' 280 browser_addons: 'Add-On-uri de Browser'
257 mobile_apps: 'Aplicații mobile' 281 mobile_apps: 'Aplicații mobile'
@@ -269,6 +293,33 @@ howto:
269 windows: 'prin Microsoft Store' 293 windows: 'prin Microsoft Store'
270 bookmarklet: 294 bookmarklet:
271 description: 'Drag &amp; drop acest link în bara de bookmark-uri:' 295 description: 'Drag &amp; drop acest link în bara de bookmark-uri:'
296 shortcuts:
297 # page_description: Here are the shortcuts available in wallabag.
298 # shortcut: Shortcut
299 # action: Action
300 # all_pages_title: Shortcuts available in all pages
301 # go_unread: Go to unread
302 # go_starred: Go to starred
303 # go_archive: Go to archive
304 # go_all: Go to all entries
305 # go_tags: Go to tags
306 # go_config: Go to config
307 # go_import: Go to import
308 # go_developers: Go to developers
309 # go_howto: Go to howto (this page!)
310 # go_logout: Logout
311 # list_title: Shortcuts available in listing pages
312 # search: Display the search form
313 # article_title: Shortcuts available in entry view
314 # open_original: Open original URL of the entry
315 # toggle_favorite: Toggle star status for the entry
316 # toggle_archive: Toggle read status for the entry
317 # delete: Delete the entry
318 # material_title: Shortcuts available with Material theme only
319 # add_link: Add a new link
320 # hide_form: Hide the current form (search or new link)
321 # arrows_navigation: Navigate through articles
322 # open_article: Display the selected entry
272 323
273quickstart: 324quickstart:
274 # page_title: 'Quickstart' 325 # page_title: 'Quickstart'
@@ -329,6 +380,9 @@ tag:
329 list: 380 list:
330 # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.' 381 # number_on_the_page: '{0} There is no tag.|{1} There is one tag.|]1,Inf[ There are %count% tags.'
331 # see_untagged_entries: 'See untagged entries' 382 # see_untagged_entries: 'See untagged entries'
383 new:
384 # add: 'Add'
385 # placeholder: 'You can add several tags, separated by a comma.'
332 386
333import: 387import:
334 # page_title: 'Import' 388 # page_title: 'Import'
@@ -362,6 +416,7 @@ import:
362 # how_to: 'Please select your Readability export and click on the below button to upload and import it.' 416 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
363 worker: 417 worker:
364 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" 418 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
419 # download_images_warning: "You enabled downloading images for your articles. Combined with classic import it can take ages to proceed (or maybe failed). We <strong>strongly recommend</strong> to enable asynchronous import to avoid errors."
365 # firefox: 420 # firefox:
366 # page_title: 'Import > Firefox' 421 # page_title: 'Import > Firefox'
367 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file." 422 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
@@ -374,6 +429,10 @@ import:
374 # page_title: 'Import > Instapaper' 429 # page_title: 'Import > Instapaper'
375 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").' 430 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
376 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.' 431 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
432 pinboard:
433 # page_title: "Import > Pinboard"
434 # description: 'This importer will import all your Instapaper articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").'
435 # how_to: 'Please select your Pinboard export and click on the below button to upload and import it.'
377 436
378developer: 437developer:
379 # page_title: 'Developer' 438 # page_title: 'Developer'
@@ -465,8 +524,10 @@ flashes:
465 rss_updated: 'Informație RSS actualizată' 524 rss_updated: 'Informație RSS actualizată'
466 # tagging_rules_updated: 'Tagging rules updated' 525 # tagging_rules_updated: 'Tagging rules updated'
467 # tagging_rules_deleted: 'Tagging rule deleted' 526 # tagging_rules_deleted: 'Tagging rule deleted'
468 # user_added: 'User "%username%" added'
469 # rss_token_updated: 'RSS token updated' 527 # rss_token_updated: 'RSS token updated'
528 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset
530 # entries_reset: Entries reset
470 entry: 531 entry:
471 notice: 532 notice:
472 # entry_already_saved: 'Entry already saved on %date%' 533 # entry_already_saved: 'Entry already saved on %date%'
@@ -496,3 +557,8 @@ flashes:
496 notice: 557 notice:
497 # client_created: 'New client created.' 558 # client_created: 'New client created.'
498 # client_deleted: 'Client deleted' 559 # client_deleted: 'Client deleted'
560 user:
561 notice:
562 # added: 'User "%username%" added'
563 # updated: 'User "%username%" updated'
564 # deleted: 'User "%username%" deleted'
diff --git a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
index 357aa2ae..74601f4e 100644
--- a/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
+++ b/src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
@@ -70,7 +70,12 @@ config:
70 # 200_word: 'I read ~200 words per minute' 70 # 200_word: 'I read ~200 words per minute'
71 # 300_word: 'I read ~300 words per minute' 71 # 300_word: 'I read ~300 words per minute'
72 # 400_word: 'I read ~400 words per minute' 72 # 400_word: 'I read ~400 words per minute'
73 action_mark_as_read:
74 # label: 'Where do you to be redirected after mark an article as read?'
75 # redirect_homepage: 'To the homepage'
76 # redirect_current_page: 'To the current page'
73 # pocket_consumer_key_label: Consumer key for Pocket to import contents 77 # pocket_consumer_key_label: Consumer key for Pocket to import contents
78 # android_configuration: Configure your Android application
74 # help_theme: "wallabag is customizable. You can choose your prefered theme here." 79 # help_theme: "wallabag is customizable. You can choose your prefered theme here."
75 # help_items_per_page: "You can change the number of articles displayed on each page." 80 # help_items_per_page: "You can change the number of articles displayed on each page."
76 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article." 81 # help_reading_speed: "wallabag calculates a reading time for each article. You can define here, thanks to this list, if you are a fast or a slow reader. wallabag will recalculate the reading time for each article."
@@ -94,6 +99,18 @@ config:
94 email_label: 'E-posta' 99 email_label: 'E-posta'
95 twoFactorAuthentication_label: 'İki adımlı doğrulama' 100 twoFactorAuthentication_label: 'İki adımlı doğrulama'
96 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email." 101 # help_twoFactorAuthentication: "If you enable 2FA, each time you want to login to wallabag, you'll receive a code by email."
102 delete:
103 # title: Delete my account (a.k.a danger zone)
104 # description: If you remove your account, ALL your articles, ALL your tags, ALL your annotations and your account will be PERMANENTLY removed (it can't be UNDONE). You'll then be logged out.
105 # confirm: Are you really sure? (THIS CAN'T BE UNDONE)
106 # button: Delete my account
107 reset:
108 # title: Reset area (a.k.a danger zone)
109 # description: By hiting buttons below you'll have ability to remove some informations from your account. Be aware that these actions are IRREVERSIBLE.
110 # annotations: Remove ALL annotations
111 # tags: Remove ALL tags
112 # entries: Remove ALL entries
113 # confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
97 form_password: 114 form_password:
98 # description: "You can change your password here. Your new password should by at least 8 characters long." 115 # description: "You can change your password here. Your new password should by at least 8 characters long."
99 old_password_label: 'Eski şifre' 116 old_password_label: 'Eski şifre'
@@ -103,6 +120,7 @@ config:
103 # if_label: 'if' 120 # if_label: 'if'
104 # then_tag_as_label: 'then tag as' 121 # then_tag_as_label: 'then tag as'
105 # delete_rule_label: 'delete' 122 # delete_rule_label: 'delete'
123 # edit_rule_label: 'edit'
106 rule_label: 'Kural' 124 rule_label: 'Kural'
107 tags_label: 'Etiketler' 125 tags_label: 'Etiketler'
108 faq: 126 faq:
@@ -144,6 +162,7 @@ entry:
144 # archived: 'Archived entries' 162 # archived: 'Archived entries'
145 # filtered: 'Filtered entries' 163 # filtered: 'Filtered entries'
146 # filtered_tags: 'Filtered by tags:' 164 # filtered_tags: 'Filtered by tags:'
165 # filtered_search: 'Filtered by search:'
147 # untagged: 'Untagged entries' 166 # untagged: 'Untagged entries'
148 list: 167 list:
149 number_on_the_page: '{0} Herhangi bir makale yok.|{1} Burada bir adet makale var.|]1,Inf[ Burada %count% adet makale var.' 168 number_on_the_page: '{0} Herhangi bir makale yok.|{1} Burada bir adet makale var.|]1,Inf[ Burada %count% adet makale var.'
@@ -167,6 +186,7 @@ entry:
167 preview_picture_label: 'Resim önizlemesi varsa' 186 preview_picture_label: 'Resim önizlemesi varsa'
168 preview_picture_help: 'Resim önizlemesi' 187 preview_picture_help: 'Resim önizlemesi'
169 language_label: 'Dil' 188 language_label: 'Dil'
189 # http_status_label: 'HTTP status'
170 reading_time: 190 reading_time:
171 label: 'Dakika cinsinden okuma süresi' 191 label: 'Dakika cinsinden okuma süresi'
172 from: 'başlangıç' 192 from: 'başlangıç'
@@ -208,6 +228,8 @@ entry:
208 placeholder: 'http://website.com' 228 placeholder: 'http://website.com'
209 form_new: 229 form_new:
210 url_label: Url 230 url_label: Url
231 search:
232 # placeholder: 'What are you looking for?'
211 edit: 233 edit:
212 page_title: 'Makaleyi düzenle' 234 page_title: 'Makaleyi düzenle'
213 title_label: 'Başlık' 235 title_label: 'Başlık'
@@ -251,6 +273,9 @@ about:
251howto: 273howto:
252 page_title: 'Yardım' 274 page_title: 'Yardım'
253 # page_description: 'There are several ways to save an article:' 275 # page_description: 'There are several ways to save an article:'
276 tab_menu:
277 # add_link: "Add a link"
278 # shortcuts: "Use shortcuts"
254 top_menu: 279 top_menu:
255 browser_addons: 'Tarayıcı eklentileri' 280 browser_addons: 'Tarayıcı eklentileri'
256 mobile_apps: 'Mobil uygulamalar' 281 mobile_apps: 'Mobil uygulamalar'
@@ -268,6 +293,33 @@ howto:
268 # windows: 'on the Microsoft Store' 293 # windows: 'on the Microsoft Store'
269 bookmarklet: 294 bookmarklet:
270 description: "Bu bağlantı ile yer imlerinizi sürükleyip bırakarak wallabag'e ekleyebilirsiniz:" 295 description: "Bu bağlantı ile yer imlerinizi sürükleyip bırakarak wallabag'e ekleyebilirsiniz:"
296 shortcuts:
297 # page_description: Here are the shortcuts available in wallabag.
298 # shortcut: Shortcut
299 # action: Action
300 # all_pages_title: Shortcuts available in all pages
301 # go_unread: Go to unread
302 # go_starred: Go to starred
303 # go_archive: Go to archive
304 # go_all: Go to all entries
305 # go_tags: Go to tags
306 # go_config: Go to config
307 # go_import: Go to import
308 # go_developers: Go to developers
309 # go_howto: Go to howto (this page!)
310 # go_logout: Logout
311 # list_title: Shortcuts available in listing pages
312 # search: Display the search form
313 # article_title: Shortcuts available in entry view
314 # open_original: Open original URL of the entry
315 # toggle_favorite: Toggle star status for the entry
316 # toggle_archive: Toggle read status for the entry
317 # delete: Delete the entry
318 # material_title: Shortcuts available with Material theme only
319 # add_link: Add a new link
320 # hide_form: Hide the current form (search or new link)
321 # arrows_navigation: Navigate through articles
322 # open_article: Display the selected entry
271 323
272quickstart: 324quickstart:
273 page_title: 'Hızlı başlangıç' 325 page_title: 'Hızlı başlangıç'
@@ -328,6 +380,9 @@ tag:
328 list: 380 list:
329 number_on_the_page: '{0} Herhangi bir etiket yok.|{1} Burada bir adet etiket var.|]1,Inf[ Burada %count% adet etiket var.' 381 number_on_the_page: '{0} Herhangi bir etiket yok.|{1} Burada bir adet etiket var.|]1,Inf[ Burada %count% adet etiket var.'
330 # see_untagged_entries: 'See untagged entries' 382 # see_untagged_entries: 'See untagged entries'
383 new:
384 # add: 'Add'
385 # placeholder: 'You can add several tags, separated by a comma.'
331 386
332import: 387import:
333 page_title: 'İçe Aktar' 388 page_title: 'İçe Aktar'
@@ -361,6 +416,7 @@ import:
361 # how_to: 'Please select your Readability export and click on the below button to upload and import it.' 416 # how_to: 'Please select your Readability export and click on the below button to upload and import it.'
362 worker: 417 worker:
363 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:" 418 # enabled: "Import is made asynchronously. Once the import task is started, an external worker will handle jobs one at a time. The current service is:"
419 # download_images_warning: "You enabled downloading images for your articles. Combined with classic import it can take ages to proceed (or maybe failed). We <strong>strongly recommend</strong> to enable asynchronous import to avoid errors."
364 firefox: 420 firefox:
365 page_title: 'İçe Aktar > Firefox' 421 page_title: 'İçe Aktar > Firefox'
366 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file." 422 # description: "This importer will import all your Firefox bookmarks. Just go to your bookmarks (Ctrl+Maj+O), then into \"Import and backup\", choose \"Backup...\". You will obtain a .json file."
@@ -373,6 +429,10 @@ import:
373 page_title: 'İçe Aktar > Instapaper' 429 page_title: 'İçe Aktar > Instapaper'
374 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").' 430 # description: 'This importer will import all your Instapaper articles. On the settings (https://www.instapaper.com/user) page, click on "Download .CSV file" in the "Export" section. A CSV file will be downloaded (like "instapaper-export.csv").'
375 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.' 431 # how_to: 'Please select your Instapaper export and click on the below button to upload and import it.'
432 pinboard:
433 # page_title: "Import > Pinboard"
434 # description: 'This importer will import all your Instapaper articles. On the backup (https://pinboard.in/settings/backup) page, click on "JSON" in the "Bookmarks" section. A JSON file will be downloaded (like "pinboard_export").'
435 # how_to: 'Please select your Pinboard export and click on the below button to upload and import it.'
376 436
377developer: 437developer:
378 # page_title: 'Developer' 438 # page_title: 'Developer'
@@ -464,8 +524,10 @@ flashes:
464 rss_updated: 'RSS bilgiler güncellendi' 524 rss_updated: 'RSS bilgiler güncellendi'
465 tagging_rules_updated: 'Tagging rules updated' 525 tagging_rules_updated: 'Tagging rules updated'
466 tagging_rules_deleted: 'Tagging rule deleted' 526 tagging_rules_deleted: 'Tagging rule deleted'
467 user_added: 'User "%username%" added'
468 rss_token_updated: 'RSS token updated' 527 rss_token_updated: 'RSS token updated'
528 # annotations_reset: Annotations reset
529 # tags_reset: Tags reset
530 # entries_reset: Entries reset
469 entry: 531 entry:
470 notice: 532 notice:
471 entry_already_saved: 'Entry already saved on %date%' 533 entry_already_saved: 'Entry already saved on %date%'
@@ -495,3 +557,8 @@ flashes:
495 notice: 557 notice:
496 # client_created: 'New client created.' 558 # client_created: 'New client created.'
497 # client_deleted: 'Client deleted' 559 # client_deleted: 'Client deleted'
560 user:
561 notice:
562 # added: 'User "%username%" added'
563 # updated: 'User "%username%" updated'
564 # deleted: 'User "%username%" deleted'
diff --git a/src/Wallabag/CoreBundle/Resources/views/base.html.twig b/src/Wallabag/CoreBundle/Resources/views/base.html.twig
index a1a9a136..289458d4 100644
--- a/src/Wallabag/CoreBundle/Resources/views/base.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/base.html.twig
@@ -41,6 +41,8 @@
41 {% block css %} 41 {% block css %}
42 {% endblock %} 42 {% endblock %}
43 {% block scripts %} 43 {% block scripts %}
44 <script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script>
45 <script src="{{ path('fos_js_routing_js', { callback: 'fos.Router.setData' }) }}"></script>
44 {% endblock %} 46 {% endblock %}
45 47
46 <title>{% block title %}{% endblock %} – wallabag</title> 48 <title>{% block title %}{% endblock %} – wallabag</title>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig
index 98b0e119..3548f590 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Config/index.html.twig
@@ -47,6 +47,14 @@
47 47
48 <fieldset class="w500p inline"> 48 <fieldset class="w500p inline">
49 <div class="row"> 49 <div class="row">
50 {{ form_label(form.config.action_mark_as_read) }}
51 {{ form_errors(form.config.action_mark_as_read) }}
52 {{ form_widget(form.config.action_mark_as_read) }}
53 </div>
54 </fieldset>
55
56 <fieldset class="w500p inline">
57 <div class="row">
50 {{ form_label(form.config.language) }} 58 {{ form_label(form.config.language) }}
51 {{ form_errors(form.config.language) }} 59 {{ form_errors(form.config.language) }}
52 {{ form_widget(form.config.language) }} 60 {{ form_widget(form.config.language) }}
@@ -71,6 +79,19 @@
71 </a> 79 </a>
72 </fieldset> 80 </fieldset>
73 81
82 <fieldset class="w500p inline">
83 <div class="row">
84 <h3>{{ 'config.form_settings.android_configuration'|trans }}</h3>
85 <a href="wallabag://{{ app.user.username }}@{{ wallabag_url }}" >Touch here to prefill your Android application</a>
86 <br/>
87 <img id="androidQrcode" />
88 <script>
89 const imgBase64 = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}');
90 document.getElementById('androidQrcode').src = imgBase64;
91 </script>
92 </div>
93 </fieldset>
94
74 {{ form_rest(form.config) }} 95 {{ form_rest(form.config) }}
75 </form> 96 </form>
76 97
@@ -164,10 +185,41 @@
164 </fieldset> 185 </fieldset>
165 {% endif %} 186 {% endif %}
166 187
188 <h2>{{ 'config.reset.title'|trans }}</h2>
189 <fieldset class="w500p inline">
190 <p>{{ 'config.reset.description'|trans }}</p>
191 <ul>
192 <li>
193 <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
194 {{ 'config.reset.annotations'|trans }}
195 </a>
196 </li>
197 <li>
198 <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
199 {{ 'config.reset.tags'|trans }}
200 </a>
201 </li>
202 <li>
203 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
204 {{ 'config.reset.entries'|trans }}
205 </a>
206 </li>
207 </ul>
208 </fieldset>
209
167 {{ form_widget(form.user._token) }} 210 {{ form_widget(form.user._token) }}
168 {{ form_widget(form.user.save) }} 211 {{ form_widget(form.user.save) }}
169 </form> 212 </form>
170 213
214 {% if enabled_users > 1 %}
215 <h2>{{ 'config.form_user.delete.title'|trans }}</h2>
216
217 <p>{{ 'config.form_user.delete.description'|trans }}</p>
218 <a href="{{ path('delete_account') }}" onclick="return confirm('{{ 'config.form_user.delete.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red delete-account">
219 {{ 'config.form_user.delete.button'|trans }}
220 </a>
221 {% endif %}
222
171 <h2>{{ 'config.tab_menu.password'|trans }}</h2> 223 <h2>{{ 'config.tab_menu.password'|trans }}</h2>
172 224
173 {{ form_start(form.pwd) }} 225 {{ form_start(form.pwd) }}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
index 56a0faac..a13fe903 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig
@@ -1,11 +1,14 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %} 1{% extends "WallabagCoreBundle::layout.html.twig" %}
2 2
3{% block title %} 3{% block title %}
4 {% set currentTag = '' %} 4 {% set filter = '' %}
5 {% if tag is defined %} 5 {% if tag is defined %}
6 {% set currentTag = tag %} 6 {% set filter = tag %}
7 {% endif %} 7 {% endif %}
8 {% include "@WallabagCore/themes/common/Entry/_title.html.twig" with {'currentTag': currentTag} %} 8 {% if searchTerm is defined and searchTerm is not empty %}
9 {% set filter = searchTerm %}
10 {% endif %}
11 {% include "@WallabagCore/themes/common/Entry/_title.html.twig" with {'filter': filter} %}
9{% endblock %} 12{% endblock %}
10 13
11{% block content %} 14{% block content %}
@@ -131,6 +134,13 @@
131 </div> 134 </div>
132 </div> 135 </div>
133 136
137 <div id="filter-http-status" class="filter-group">
138 {{ form_label(form.httpStatus) }}
139 <div class="input-field ">
140 {{ form_widget(form.httpStatus) }}
141 </div>
142 </div>
143
134 <div id="filter-reading-time" class="filter-group"> 144 <div id="filter-reading-time" class="filter-group">
135 <div class=""> 145 <div class="">
136 {{ form_label(form.readingTime) }} 146 {{ form_label(form.readingTime) }}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig
index 3689159b..2e9673d5 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entry.html.twig
@@ -11,7 +11,7 @@
11 <div id="article_toolbar"> 11 <div id="article_toolbar">
12 <ul class="links"> 12 <ul class="links">
13 <li class="topPosF"><a href="#top" title="{{ 'entry.view.left_menu.back_to_top'|trans }}" class="tool top icon icon-arrow-up-thick"><span>{{ 'entry.view.left_menu.set_as_read'|trans }}</span></a></li> 13 <li class="topPosF"><a href="#top" title="{{ 'entry.view.left_menu.back_to_top'|trans }}" class="tool top icon icon-arrow-up-thick"><span>{{ 'entry.view.left_menu.set_as_read'|trans }}</span></a></li>
14 <li><a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e }}" class="tool link icon icon-link"><span>{{ entry.domainName|removeWww }}</span></a></li> 14 <li><a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e }}" class="tool link icon icon-link original"><span>{{ entry.domainName|removeWww }}</span></a></li>
15 <li><a title="{{ 'entry.view.left_menu.re_fetch_content'|trans }}" class="tool icon icon-reload" href="{{ path('reload_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.re_fetch_content'|trans }}</span></a></li> 15 <li><a title="{{ 'entry.view.left_menu.re_fetch_content'|trans }}" class="tool icon icon-reload" href="{{ path('reload_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.re_fetch_content'|trans }}</span></a></li>
16 16
17 {% set markAsReadLabel = 'entry.view.left_menu.set_as_unread' %} 17 {% set markAsReadLabel = 'entry.view.left_menu.set_as_unread' %}
@@ -19,8 +19,8 @@
19 {% set markAsReadLabel = 'entry.view.left_menu.set_as_read' %} 19 {% set markAsReadLabel = 'entry.view.left_menu.set_as_read' %}
20 {% endif %} 20 {% endif %}
21 21
22 <li><a title="{{ markAsReadLabel|trans }}" class="tool icon icon-check {% if entry.isArchived == 0 %}archive-off{% else %}archive{% endif %}" href="{{ path('archive_entry', { 'id': entry.id }) }}"><span>{{ markAsReadLabel|trans }}</span></a></li> 22 <li><a title="{{ markAsReadLabel|trans }}" class="tool icon icon-check {% if entry.isArchived == 0 %}archive-off{% else %}archive{% endif %} markasread" href="{{ path('archive_entry', { 'id': entry.id }) }}"><span>{{ markAsReadLabel|trans }}</span></a></li>
23 <li><a title="{{ 'entry.view.left_menu.set_as_starred'|trans }}" class="tool icon icon-star {% if entry.isStarred == 0 %}fav-off{% else %}fav{% endif %}" href="{{ path('star_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.set_as_starred'|trans }}</span></a></li> 23 <li><a title="{{ 'entry.view.left_menu.set_as_starred'|trans }}" class="tool icon icon-star {% if entry.isStarred == 0 %}fav-off{% else %}fav{% endif %} favorite" href="{{ path('star_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.set_as_starred'|trans }}</span></a></li>
24 <li><a id="nav-btn-add-tag" class="tool icon icon-price-tags" title="{{ 'entry.view.left_menu.add_a_tag'|trans }}"><span>{{ 'entry.view.left_menu.add_a_tag'|trans }}</span></a></li> 24 <li><a id="nav-btn-add-tag" class="tool icon icon-price-tags" title="{{ 'entry.view.left_menu.add_a_tag'|trans }}"><span>{{ 'entry.view.left_menu.add_a_tag'|trans }}</span></a></li>
25 <li><a title="{{ 'entry.view.left_menu.delete'|trans }}" class="tool delete icon icon-trash" href="{{ path('delete_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.delete'|trans }}</span></a></li> 25 <li><a title="{{ 'entry.view.left_menu.delete'|trans }}" class="tool delete icon icon-trash" href="{{ path('delete_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.delete'|trans }}</span></a></li>
26 {% if craue_setting('share_public') %} 26 {% if craue_setting('share_public') %}
@@ -31,6 +31,7 @@
31 {% if craue_setting('share_mail') %}<li><a href="mailto:?subject={{ entry.title|url_encode }}&amp;body={{ entry.url|url_encode }}%20via%20@wallabagapp" class="tool email icon icon-mail" title="Email"><span>Email</span></a></li>{% endif %} 31 {% if craue_setting('share_mail') %}<li><a href="mailto:?subject={{ entry.title|url_encode }}&amp;body={{ entry.url|url_encode }}%20via%20@wallabagapp" class="tool email icon icon-mail" title="Email"><span>Email</span></a></li>{% endif %}
32 {% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}" target="_blank" class="tool icon-image icon-image--shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %} 32 {% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}" target="_blank" class="tool icon-image icon-image--shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %}
33 {% if craue_setting('share_diaspora') %}<li><a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&notes=&v=1&noui=1&jump=doclose" target="_blank" class="tool diaspora icon-image icon-image--diaspora" title="diaspora"><span>diaspora</span></a></li>{% endif %} 33 {% if craue_setting('share_diaspora') %}<li><a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&notes=&v=1&noui=1&jump=doclose" target="_blank" class="tool diaspora icon-image icon-image--diaspora" title="diaspora"><span>diaspora</span></a></li>{% endif %}
34 {% if craue_setting('share_unmark') %}<li><a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|url_encode}}&amp;v=6" target="_blank" class="tool unmark icon-image icon-image--unmark" title="unmark"><span>unmark.it</span></a></li>{% endif %}
34 {% if craue_setting('carrot') %}<li><a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}" class="tool carrot icon-image icon-image--carrot" target="_blank" title="carrot"><span>Carrot</span></a></li>{% endif %} 35 {% if craue_setting('carrot') %}<li><a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}" class="tool carrot icon-image icon-image--carrot" target="_blank" title="carrot"><span>Carrot</span></a></li>{% endif %}
35 {% if craue_setting('show_printlink') %}<li><a title="{{ 'entry.view.left_menu.print'|trans }}" class="tool icon icon-print" href="javascript: window.print();"><span>{{ 'entry.view.left_menu.print'|trans }}</span></a></li>{% endif %} 36 {% if craue_setting('show_printlink') %}<li><a title="{{ 'entry.view.left_menu.print'|trans }}" class="tool icon icon-print" href="javascript: window.print();"><span>{{ 'entry.view.left_menu.print'|trans }}</span></a></li>{% endif %}
36 {% if craue_setting('export_epub') %}<li><a href="?epub&amp;method=id&amp;value={{ entry.id }}" title="Generate ePub file">EPUB</a></li>{% endif %} 37 {% if craue_setting('export_epub') %}<li><a href="?epub&amp;method=id&amp;value={{ entry.id }}" title="Generate ePub file">EPUB</a></li>{% endif %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/search_form.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/search_form.html.twig
new file mode 100644
index 00000000..20821b6d
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/search_form.html.twig
@@ -0,0 +1,17 @@
1<form name="search" method="GET" action="{{ path('search')}}">
2 <h2>{{ 'menu.left.search'|trans }}</h2>
3 <a href="javascript: void(null);" id="search-form-close" class="close-button--popup close-button">&times;</a>
4 {% if form_errors(form) %}
5 <span class="black-text">{{ form_errors(form) }}</span>
6 {% endif %}
7
8 {% if form_errors(form.term) %}
9 <span class="black-text">{{ form_errors(form.term) }}</span>
10 {% endif %}
11
12 <input type="hidden" name="currentRoute" value="{{ currentRoute }}" />
13
14 {{ form_widget(form.term, { 'attr': {'autocomplete': 'off', 'placeholder': 'entry.search.placeholder'} }) }}
15
16 {{ form_rest(form) }}
17</form>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
index cd4ed3fa..07ff8e14 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/layout.html.twig
@@ -31,17 +31,11 @@
31 <li class="menu all"><a href="{{ path('all') }}">{{ 'menu.left.all_articles'|trans }}</a></li> 31 <li class="menu all"><a href="{{ path('all') }}">{{ 'menu.left.all_articles'|trans }}</a></li>
32 <li class="menu tag"><a href="{{ path('tag') }}">{{ 'menu.left.tags'|trans }}</a></li> 32 <li class="menu tag"><a href="{{ path('tag') }}">{{ 'menu.left.tags'|trans }}</a></li>
33 <li class="menu new"><a href="{{ path('new') }}">{{ 'menu.left.save_link'|trans }}</a></li> 33 <li class="menu new"><a href="{{ path('new') }}">{{ 'menu.left.save_link'|trans }}</a></li>
34 <!--<li style="position: relative;"><a href="javascript: void(null);" id="search">{{ 'menu.left.search'|trans }}</a> 34 <li style="position: relative;"><a href="javascript: void(null);" id="search">{{ 'menu.left.search'|trans }}</a>
35 <div id="search-form" class="messages info popup-form"> 35 <div id="search-form" class="messages info popup-form">
36 <form method="get" action="index.php"> 36 {{ render(controller("WallabagCoreBundle:Entry:searchForm", {'currentRoute': app.request.attributes.get('_route')})) }}
37 <h2>{{ 'menu.left.search'|trans }}</h2>
38 <a href="javascript: void(null);" id="search-form-close" class="close-button--popup close-button">&times;</a>
39 <input type="hidden" name="view" value="search">
40 <input required placeholder="{{ 'menu.search_form.input_label'|trans }}" type="text" name="search" id="searchfield"><br>
41 <input id="submit-search" type="submit" value="{{ 'menu.left.search'|trans }}">
42 </form>
43 </div> 37 </div>
44 </li>--> 38 </li>
45 <li class="menu config"><a href="{{ path('config') }}">{{ 'menu.left.config'|trans }}</a></li> 39 <li class="menu config"><a href="{{ path('config') }}">{{ 'menu.left.config'|trans }}</a></li>
46 {% if is_granted('ROLE_SUPER_ADMIN') %} 40 {% if is_granted('ROLE_SUPER_ADMIN') %}
47 <li class="menu users"><a href="{{ path('user_index') }}">{{ 'menu.left.users_management'|trans }}</a></li> 41 <li class="menu users"><a href="{{ path('user_index') }}">{{ 'menu.left.users_management'|trans }}</a></li>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_title.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_title.html.twig
index 92cabdd9..654c1d2d 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_title.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_title.html.twig
@@ -6,8 +6,10 @@
6 {{ 'entry.page_titles.archived'|trans }} 6 {{ 'entry.page_titles.archived'|trans }}
7{% elseif currentRoute == 'all' %} 7{% elseif currentRoute == 'all' %}
8 {{ 'entry.page_titles.filtered'|trans }} 8 {{ 'entry.page_titles.filtered'|trans }}
9{% elseif currentRoute == 'search' %}
10 {{ 'entry.page_titles.filtered_search'|trans }} {{ filter }}
9{% elseif currentRoute == 'tag_entries' %} 11{% elseif currentRoute == 'tag_entries' %}
10 {{ 'entry.page_titles.filtered_tags'|trans }} {{ currentTag }} 12 {{ 'entry.page_titles.filtered_tags'|trans }} {{ filter }}
11{% elseif currentRoute == 'untagged' %} 13{% elseif currentRoute == 'untagged' %}
12 {{ 'entry.page_titles.untagged'|trans }} 14 {{ 'entry.page_titles.untagged'|trans }}
13{% else %} 15{% else %}
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig
index 288bb54f..16ecaa97 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/entries.xml.twig
@@ -2,7 +2,15 @@
2<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/"> 2<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
3 <channel> 3 <channel>
4 <title>wallabag — {{type}} feed</title> 4 <title>wallabag — {{type}} feed</title>
5 <link>{{ url('unread') }}</link> 5 <link>{{ url(type) }}</link>
6 <link rel="self" href="{{ app.request.uri }}"/>
7 {% if entries.hasPreviousPage -%}
8 <link rel="previous" href="{{ url }}?page={{ entries.previousPage }}"/>
9 {% endif -%}
10 {% if entries.hasNextPage -%}
11 <link rel="next" href="{{ url }}?page={{ entries.nextPage }}"/>
12 {% endif -%}
13 <link rel="last" href="{{ url }}?page={{ entries.nbPages }}"/>
6 <pubDate>{{ "now"|date('D, d M Y H:i:s') }}</pubDate> 14 <pubDate>{{ "now"|date('D, d M Y H:i:s') }}</pubDate>
7 <generator>wallabag</generator> 15 <generator>wallabag</generator>
8 <description>wallabag {{type}} elements</description> 16 <description>wallabag {{type}} elements</description>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig
index 67a10190..3b02993e 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/howto.html.twig
@@ -7,39 +7,186 @@
7 <div class="row"> 7 <div class="row">
8 <div class="col s12"> 8 <div class="col s12">
9 <div class="card-panel settings"> 9 <div class="card-panel settings">
10 <p>{{ 'howto.page_description'|trans }}</p>
11 10
12 <div class="row"> 11 <div class="row">
13 12 <div class="div_tabs col s12">
14 <div class="col s12"> 13 <ul class="tabs">
15 <a href="{{ path('new') }}">{{ 'howto.form.description'|trans }}</a> 14 <li class="tab col s12 m6 l3"><a class="active" href="#set1">{{ 'howto.tab_menu.add_link'|trans }}</a></li>
16 </div> 15 <li class="tab col s12 m6 l3"><a href="#set2">{{ 'howto.tab_menu.shortcuts'|trans }}</a></li>
17
18 <div class="col s12">
19 <h5>{{ 'howto.top_menu.browser_addons'|trans }}</h5>
20 <ul>
21 <li><a href="{{ addonsUrl.firefox }}" target="_blank">{{ 'howto.browser_addons.firefox'|trans }}</a></li>
22 <li><a href="{{ addonsUrl.chrome }}" target="_blank">{{ 'howto.browser_addons.chrome'|trans }}</a></li>
23 </ul> 16 </ul>
24 </div> 17 </div>
25 18
26 <div class="col s12"> 19 <div id="set1" class="col s12">
27 <h5>{{ 'howto.top_menu.mobile_apps'|trans }}</h5> 20 <p>{{ 'howto.page_description'|trans }}</p>
28 <ul> 21
29 <li>Android: <a href="{{ addonsUrl.f_droid }}" target="_blank">{{ 'howto.mobile_apps.android.via_f_droid'|trans }}</a> / <a href="{{ addonsUrl.google_play }}" target="_blank">{{ 'howto.mobile_apps.android.via_google_play'|trans }}</a></li> 22 <div class="row">
30 <li>iOS: <a href="{{ addonsUrl.ios }}" target="_blank">{{ 'howto.mobile_apps.ios'|trans }}</a></li>
31 <li>Windows Phone: <a href="{{ addonsUrl.windows }}" target="_blank">{{ 'howto.mobile_apps.windows'|trans }}</a></li>
32 </ul>
33 </div>
34 23
35 <div class="col s12"> 24 <div class="col s12">
36 <h5>{{ 'howto.top_menu.bookmarklet'|trans }}</h5> 25 <a href="{{ path('new') }}">{{ 'howto.form.description'|trans }}</a>
37 {{ 'howto.bookmarklet.description'|trans }} 26 </div>
38 {% include '@WallabagCore/themes/common/Static/_bookmarklet.html.twig' %} 27
28 <div class="col s12">
29 <h5>{{ 'howto.top_menu.browser_addons'|trans }}</h5>
30 <ul>
31 <li><a href="{{ addonsUrl.firefox }}" target="_blank">{{ 'howto.browser_addons.firefox'|trans }}</a></li>
32 <li><a href="{{ addonsUrl.chrome }}" target="_blank">{{ 'howto.browser_addons.chrome'|trans }}</a></li>
33 </ul>
34 </div>
35
36 <div class="col s12">
37 <h5>{{ 'howto.top_menu.mobile_apps'|trans }}</h5>
38 <ul>
39 <li>Android: <a href="{{ addonsUrl.f_droid }}" target="_blank">{{ 'howto.mobile_apps.android.via_f_droid'|trans }}</a> / <a href="{{ addonsUrl.google_play }}" target="_blank">{{ 'howto.mobile_apps.android.via_google_play'|trans }}</a></li>
40 <li>iOS: <a href="{{ addonsUrl.ios }}" target="_blank">{{ 'howto.mobile_apps.ios'|trans }}</a></li>
41 <li>Windows Phone: <a href="{{ addonsUrl.windows }}" target="_blank">{{ 'howto.mobile_apps.windows'|trans }}</a></li>
42 </ul>
43 </div>
44
45 <div class="col s12">
46 <h5>{{ 'howto.top_menu.bookmarklet'|trans }}</h5>
47 {{ 'howto.bookmarklet.description'|trans }}
48 {% include '@WallabagCore/themes/common/Static/_bookmarklet.html.twig' %}
49 </div>
50
51 </div>
39 </div> 52 </div>
40 53
41 </div> 54 <div id="set2" class="col s12">
55 <p>{{ 'howto.shortcuts.page_description'|trans }}</p>
56
57 <h5>{{ 'howto.shortcuts.all_pages_title'|trans }}</h5>
42 58
59 <table class="bordered">
60 <thead>
61 <tr>
62 <th>{{ 'howto.shortcuts.shortcut'|trans }}</th>
63 <th>{{ 'howto.shortcuts.action'|trans }}</th>
64 </tr>
65 </thead>
66
67 <tbody>
68 <tr>
69 <td><code>g u</code></td>
70 <td>{{ 'howto.shortcuts.go_unread'|trans }}</td>
71 </tr>
72 <tr>
73 <td><code>g s</code></td>
74 <td>{{ 'howto.shortcuts.go_starred'|trans }}</td>
75 </tr>
76 <tr>
77 <td><code>g r</code></td>
78 <td>{{ 'howto.shortcuts.go_archive'|trans }}</td>
79 </tr>
80 <tr>
81 <td><code>g a</code></td>
82 <td>{{ 'howto.shortcuts.go_all'|trans }}</td>
83 </tr>
84 <tr>
85 <td><code>g t</code></td>
86 <td>{{ 'howto.shortcuts.go_tags'|trans }}</td>
87 </tr>
88 <tr>
89 <td><code>g c</code></td>
90 <td>{{ 'howto.shortcuts.go_config'|trans }}</td>
91 </tr>
92 <tr>
93 <td><code>g i</code></td>
94 <td>{{ 'howto.shortcuts.go_import'|trans }}</td>
95 </tr>
96 <tr>
97 <td><code>g d</code></td>
98 <td>{{ 'howto.shortcuts.go_developers'|trans }}</td>
99 </tr>
100 <tr>
101 <td><code>?</code></td>
102 <td>{{ 'howto.shortcuts.go_howto'|trans }}</td>
103 </tr>
104 <tr>
105 <td><code>g l</code></td>
106 <td>{{ 'howto.shortcuts.go_logout'|trans }}</td>
107 </tr>
108 </tbody>
109 </table>
110
111 <h5>{{ 'howto.shortcuts.list_title'|trans }}</h5>
112
113 <table class="bordered">
114 <thead>
115 <tr>
116 <th>{{ 'howto.shortcuts.shortcut'|trans }}</th>
117 <th>{{ 'howto.shortcuts.action'|trans }}</th>
118 </tr>
119 </thead>
120
121 <tbody>
122 <tr>
123 <td><code>s</code></td>
124 <td>{{ 'howto.shortcuts.search'|trans }}</td>
125 </tr>
126 </tbody>
127 </table>
128
129 <h5>{{ 'howto.shortcuts.article_title'|trans }}</h5>
130
131 <table class="bordered">
132 <thead>
133 <tr>
134 <th>{{ 'howto.shortcuts.shortcut'|trans }}</th>
135 <th>{{ 'howto.shortcuts.action'|trans }}</th>
136 </tr>
137 </thead>
138
139 <tbody>
140 <tr>
141 <td><code>o</code></td>
142 <td>{{ 'howto.shortcuts.open_original'|trans }}</td>
143 </tr>
144 <tr>
145 <td><code>f</code></td>
146 <td>{{ 'howto.shortcuts.toggle_favorite'|trans }}</td>
147 </tr>
148 <tr>
149 <td><code>a</code></td>
150 <td>{{ 'howto.shortcuts.toggle_archive'|trans }}</td>
151 </tr>
152 <tr>
153 <td><code>del</code></td>
154 <td>{{ 'howto.shortcuts.delete'|trans }}</td>
155 </tr>
156 </tbody>
157 </table>
158
159 <h5>{{ 'howto.shortcuts.material_title'|trans }}</h5>
160
161 <table class="bordered">
162 <thead>
163 <tr>
164 <th>{{ 'howto.shortcuts.shortcut'|trans }}</th>
165 <th>{{ 'howto.shortcuts.action'|trans }}</th>
166 </tr>
167 </thead>
168
169 <tbody>
170 <tr>
171 <td><code>g n</code></td>
172 <td>{{ 'howto.shortcuts.add_link'|trans }}</td>
173 </tr>
174 <tr>
175 <td><code>esc</code></td>
176 <td>{{ 'howto.shortcuts.hide_form'|trans }}</td>
177 </tr>
178 <tr>
179 <td><code>← →</code></td>
180 <td>{{ 'howto.shortcuts.arrows_navigation'|trans }}</td>
181 </tr>
182 <tr>
183 <td><code>enter</code></td>
184 <td>{{ 'howto.shortcuts.open_article'|trans }}</td>
185 </tr>
186 </tbody>
187 </table>
188 </div>
189
43 </div> 190 </div>
44 </div> 191 </div>
45 </div> 192 </div>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig
index c8a303a6..b7a48551 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/common/Static/quickstart.html.twig
@@ -15,7 +15,7 @@
15 <li class="col l4 m6 s12"> 15 <li class="col l4 m6 s12">
16 <div class="card teal darken-1"> 16 <div class="card teal darken-1">
17 <div class="card-content white-text"> 17 <div class="card-content white-text">
18 <span class="card-title">{{ 'quickstart.configure.title'|trans }}</span> 18 <span class="card-title white-text">{{ 'quickstart.configure.title'|trans }}</span>
19 <p>{{ 'quickstart.configure.description'|trans }}</p> 19 <p>{{ 'quickstart.configure.description'|trans }}</p>
20 </div> 20 </div>
21 <div class="card-action"> 21 <div class="card-action">
@@ -31,7 +31,7 @@
31 <li class="col l4 m6 s12"> 31 <li class="col l4 m6 s12">
32 <div class="card green darken-1"> 32 <div class="card green darken-1">
33 <div class="card-content white-text"> 33 <div class="card-content white-text">
34 <span class="card-title">{{ 'quickstart.first_steps.title'|trans }}</span> 34 <span class="card-title white-text">{{ 'quickstart.first_steps.title'|trans }}</span>
35 <p>{{ 'quickstart.first_steps.description'|trans }}</p> 35 <p>{{ 'quickstart.first_steps.description'|trans }}</p>
36 </div> 36 </div>
37 <div class="card-action"> 37 <div class="card-action">
@@ -46,7 +46,7 @@
46 <li class="col l4 m6 s12"> 46 <li class="col l4 m6 s12">
47 <div class="card light-green darken-1"> 47 <div class="card light-green darken-1">
48 <div class="card-content white-text"> 48 <div class="card-content white-text">
49 <span class="card-title">{{ 'quickstart.migrate.title'|trans }}</span> 49 <span class="card-title white-text">{{ 'quickstart.migrate.title'|trans }}</span>
50 <p>{{ 'quickstart.migrate.description'|trans }}</p> 50 <p>{{ 'quickstart.migrate.description'|trans }}</p>
51 </div> 51 </div>
52 <div class="card-action"> 52 <div class="card-action">
@@ -63,7 +63,7 @@
63 <li class="col l4 m6 s12"> 63 <li class="col l4 m6 s12">
64 <div class="card blue darken-1"> 64 <div class="card blue darken-1">
65 <div class="card-content white-text"> 65 <div class="card-content white-text">
66 <span class="card-title">{{ 'quickstart.developer.title'|trans }}</span> 66 <span class="card-title white-text">{{ 'quickstart.developer.title'|trans }}</span>
67 <p>{{ 'quickstart.developer.description'|trans }}</p> 67 <p>{{ 'quickstart.developer.description'|trans }}</p>
68 </div> 68 </div>
69 <div class="card-action"> 69 <div class="card-action">
@@ -79,7 +79,7 @@
79 <li class="col l4 m6 s12"> 79 <li class="col l4 m6 s12">
80 <div class="card light-blue darken-1"> 80 <div class="card light-blue darken-1">
81 <div class="card-content white-text"> 81 <div class="card-content white-text">
82 <span class="card-title">{{ 'quickstart.docs.title'|trans }}</span> 82 <span class="card-title white-text">{{ 'quickstart.docs.title'|trans }}</span>
83 <p>{{ 'quickstart.docs.description'|trans }}</p> 83 <p>{{ 'quickstart.docs.description'|trans }}</p>
84 </div> 84 </div>
85 <div class="card-action"> 85 <div class="card-action">
@@ -95,7 +95,7 @@
95 <li class="col l4 m6 s12"> 95 <li class="col l4 m6 s12">
96 <div class="card cyan darken-1"> 96 <div class="card cyan darken-1">
97 <div class="card-content white-text"> 97 <div class="card-content white-text">
98 <span class="card-title">{{ 'quickstart.support.title'|trans }}</span> 98 <span class="card-title white-text">{{ 'quickstart.support.title'|trans }}</span>
99 <p>{{ 'quickstart.support.description'|trans }}</p> 99 <p>{{ 'quickstart.support.description'|trans }}</p>
100 </div> 100 </div>
101 <div class="card-action"> 101 <div class="card-action">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
index 9f67217b..5d411fdd 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Config/index.html.twig
@@ -66,6 +66,14 @@
66 </div> 66 </div>
67 </div> 67 </div>
68 68
69 <div class="row">
70 <div class="input-field col s12">
71 {{ form_label(form.config.action_mark_as_read) }}
72 {{ form_errors(form.config.action_mark_as_read) }}
73 {{ form_widget(form.config.action_mark_as_read) }}
74 </div>
75 </div>
76
69 <div class="row"> 77 <div class="row">
70 <div class="input-field col s11"> 78 <div class="input-field col s11">
71 {{ form_label(form.config.language) }} 79 {{ form_label(form.config.language) }}
@@ -96,6 +104,18 @@
96 </div> 104 </div>
97 </div> 105 </div>
98 106
107 <div class="row">
108 <div class="input-field col s12">
109 <h5>{{ 'config.form_settings.android_configuration'|trans }}</h5>
110 <a href="wallabag://{{ app.user.username }}@{{ wallabag_url }}" class="waves-effect waves-light btn hide-on-large-only">Touch here to prefill your Android application</a>
111 <img id="androidQrcode" class="hide-on-med-and-down" />
112 </div>
113 <script>
114 const imgBase64 = jrQrcode.getQrBase64('wallabag://{{ app.user.username }}@{{ wallabag_url }}');
115 document.getElementById('androidQrcode').src = imgBase64;
116 </script>
117 </div>
118
99 {{ form_widget(form.config.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} 119 {{ form_widget(form.config.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
100 {{ form_rest(form.config) }} 120 {{ form_rest(form.config) }}
101 </form> 121 </form>
@@ -197,6 +217,34 @@
197 {{ form_widget(form.user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }} 217 {{ form_widget(form.user.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
198 {{ form_widget(form.user._token) }} 218 {{ form_widget(form.user._token) }}
199 </form> 219 </form>
220
221 <br /><hr /><br />
222
223 <div class="row">
224 <h5>{{ 'config.reset.title'|trans }}</h5>
225 <p>{{ 'config.reset.description'|trans }}</p>
226 <a href="{{ path('config_reset', { type: 'annotations'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
227 {{ 'config.reset.annotations'|trans }}
228 </a>
229 <a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
230 {{ 'config.reset.tags'|trans }}
231 </a>
232 <a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
233 {{ 'config.reset.entries'|trans }}
234 </a>
235 </div>
236
237 {% if enabled_users > 1 %}
238 <br /><hr /><br />
239
240 <div class="row">
241 <h5>{{ 'config.form_user.delete.title'|trans }}</h5>
242 <p>{{ 'config.form_user.delete.description'|trans }}</p>
243 <a href="{{ path('delete_account') }}" onclick="return confirm('{{ 'config.form_user.delete.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red delete-account">
244 {{ 'config.form_user.delete.button'|trans }}
245 </a>
246 </div>
247 {% endif %}
200 </div> 248 </div>
201 249
202 <div id="set4" class="col s12"> 250 <div id="set4" class="col s12">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
index c610c8d2..00e8bf63 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig
@@ -1,11 +1,14 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %} 1{% extends "WallabagCoreBundle::layout.html.twig" %}
2 2
3{% block title %} 3{% block title %}
4 {% set currentTag = '' %} 4 {% set filter = '' %}
5 {% if tag is defined %} 5 {% if tag is defined %}
6 {% set currentTag = tag %} 6 {% set filter = tag %}
7 {% endif %}
8 {% if searchTerm is defined and searchTerm is not empty %}
9 {% set filter = searchTerm %}
7 {% endif %} 10 {% endif %}
8 {% include "@WallabagCore/themes/common/Entry/_title.html.twig" with {'currentTag': currentTag} %} 11 {% include "@WallabagCore/themes/common/Entry/_title.html.twig" with {'filter': filter} %}
9{% endblock %} 12{% endblock %}
10 13
11{% block content %} 14{% block content %}
@@ -104,6 +107,14 @@
104 </div> 107 </div>
105 108
106 <div class="col s12"> 109 <div class="col s12">
110 {{ form_label(form.httpStatus) }}
111 </div>
112
113 <div class="input-field col s12">
114 {{ form_widget(form.httpStatus) }}
115 </div>
116
117 <div class="col s12">
107 {{ form_label(form.readingTime) }} 118 {{ form_label(form.readingTime) }}
108 </div> 119 </div>
109 <div class="input-field col s6"> 120 <div class="input-field col s6">
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
index c615a907..bed0fdec 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entry.html.twig
@@ -46,14 +46,14 @@
46 </li> 46 </li>
47 47
48 <li class="bold border-bottom hide-on-med-and-down"> 48 <li class="bold border-bottom hide-on-med-and-down">
49 <a class="waves-effect collapsible-header" href="{{ entry.url|e }}"> 49 <a class="waves-effect collapsible-header original" href="{{ entry.url|e }}" target="_blank">
50 <i class="material-icons small">link</i> 50 <i class="material-icons small">link</i>
51 <span>{{ 'entry.view.left_menu.view_original_article'|trans }}</span> 51 <span>{{ 'entry.view.left_menu.view_original_article'|trans }}</span>
52 </a> 52 </a>
53 <div class="collapsible-body"></div> 53 <div class="collapsible-body"></div>
54 </li> 54 </li>
55 55
56 <li class="bold hide-on-med-and-down"> 56 <li class="bold">
57 <a class="waves-effect collapsible-header" title="{{ 'entry.view.left_menu.re_fetch_content'|trans }}" href="{{ path('reload_entry', { 'id': entry.id }) }}" id="reload"> 57 <a class="waves-effect collapsible-header" title="{{ 'entry.view.left_menu.re_fetch_content'|trans }}" href="{{ path('reload_entry', { 'id': entry.id }) }}" id="reload">
58 <i class="material-icons small">autorenew</i> 58 <i class="material-icons small">autorenew</i>
59 <span>{{ 'entry.view.left_menu.re_fetch_content'|trans }}</span> 59 <span>{{ 'entry.view.left_menu.re_fetch_content'|trans }}</span>
@@ -67,7 +67,7 @@
67 {% endif %} 67 {% endif %}
68 68
69 <li class="bold hide-on-med-and-down"> 69 <li class="bold hide-on-med-and-down">
70 <a class="waves-effect collapsible-header" title="{{ markAsReadLabel|trans }}" href="{{ path('archive_entry', { 'id': entry.id }) }}" id="markAsRead"> 70 <a class="waves-effect collapsible-header markasread" title="{{ markAsReadLabel|trans }}" href="{{ path('archive_entry', { 'id': entry.id }) }}" id="markAsRead">
71 <i class="material-icons small">{% if entry.isArchived == 0 %}done{% else %}redo{% endif %}</i> 71 <i class="material-icons small">{% if entry.isArchived == 0 %}done{% else %}redo{% endif %}</i>
72 <span>{{ markAsReadLabel|trans }}</span> 72 <span>{{ markAsReadLabel|trans }}</span>
73 </a> 73 </a>
@@ -75,21 +75,21 @@
75 </li> 75 </li>
76 76
77 <li class="bold hide-on-med-and-down"> 77 <li class="bold hide-on-med-and-down">
78 <a class="waves-effect collapsible-header" title="{{ 'entry.view.left_menu.set_as_starred'|trans }}" href="{{ path('star_entry', { 'id': entry.id }) }}" id="setFav"> 78 <a class="waves-effect collapsible-header favorite" title="{{ 'entry.view.left_menu.set_as_starred'|trans }}" href="{{ path('star_entry', { 'id': entry.id }) }}" id="setFav">
79 <i class="material-icons spall">{% if entry.isStarred == 0 %}star_outline{% else %}star{% endif %}</i> 79 <i class="material-icons spall">{% if entry.isStarred == 0 %}star_outline{% else %}star{% endif %}</i>
80 <span>{{ 'entry.view.left_menu.set_as_starred'|trans }}</span> 80 <span>{{ 'entry.view.left_menu.set_as_starred'|trans }}</span>
81 </a> 81 </a>
82 <div class="collapsible-body"></div> 82 <div class="collapsible-body"></div>
83 </li> 83 </li>
84 <li class="bold border-bottom hide-on-med-and-down"> 84 <li class="bold border-bottom">
85 <a class="waves-effect collapsible-header" title="{{ 'entry.view.left_menu.delete'|trans }}" href="{{ path('delete_entry', { 'id': entry.id }) }}"> 85 <a class="waves-effect collapsible-header delete" title="{{ 'entry.view.left_menu.delete'|trans }}" href="{{ path('delete_entry', { 'id': entry.id }) }}">
86 <i class="material-icons small">delete</i> 86 <i class="material-icons small">delete</i>
87 <span>{{ 'entry.view.left_menu.delete'|trans }}</span> 87 <span>{{ 'entry.view.left_menu.delete'|trans }}</span>
88 </a> 88 </a>
89 <div class="collapsible-body"></div> 89 <div class="collapsible-body"></div>
90 </li> 90 </li>
91 91
92 <li class="bold border-bottom hide-on-med-and-down"> 92 <li class="bold border-bottom">
93 <a class="waves-effect collapsible-header" id="nav-btn-add-tag"> 93 <a class="waves-effect collapsible-header" id="nav-btn-add-tag">
94 <i class="material-icons small">label_outline</i> 94 <i class="material-icons small">label_outline</i>
95 <span>{{ 'entry.view.left_menu.add_a_tag'|trans }}</span> 95 <span>{{ 'entry.view.left_menu.add_a_tag'|trans }}</span>
@@ -139,6 +139,14 @@
139 </a> 139 </a>
140 </li> 140 </li>
141 {% endif %} 141 {% endif %}
142 {% if craue_setting('share_unmark') %}
143 <li>
144 <a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|url_encode}}&amp;v=6" target="_blank">
145 <i class="tool icon-image icon-image--unmark" title="unmark"></i>
146 <span>unmark.it</span>
147 </a>
148 </li>
149 {% endif %}
142 {% if craue_setting('carrot') %} 150 {% if craue_setting('carrot') %}
143 <li> 151 <li>
144 <a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}" target="_blank" title="carrot"> 152 <a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}" target="_blank" title="carrot">
@@ -186,14 +194,6 @@
186 </div> 194 </div>
187 </li> 195 </li>
188 196
189 <li class="bold hide-on-large-only">
190 <a class="waves-effect collapsible-header" title="{{ 'entry.view.left_menu.delete'|trans }}" href="{{ path('delete_entry', { 'id': entry.id }) }}">
191 <i class="material-icons small">delete</i>
192 <span>{{ 'entry.view.left_menu.delete'|trans }}</span>
193 </a>
194 <div class="collapsible-body"></div>
195 </li>
196
197 <li class="bold"> 197 <li class="bold">
198 <a class="waves-effect collapsible-header" href="mailto:hello@wallabag.org?subject=Wrong%20display%20in%20wallabag&amp;body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.description'|trans }}"> 198 <a class="waves-effect collapsible-header" href="mailto:hello@wallabag.org?subject=Wrong%20display%20in%20wallabag&amp;body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.description'|trans }}">
199 <i class="material-icons small">error</i> 199 <i class="material-icons small">error</i>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/search_form.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/search_form.html.twig
new file mode 100644
index 00000000..f25de94d
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/search_form.html.twig
@@ -0,0 +1,15 @@
1<form name="search" method="GET" action="{{ path('search')}}">
2 {% if form_errors(form) %}
3 <span class="black-text">{{ form_errors(form) }}</span>
4 {% endif %}
5
6 {% if form_errors(form.term) %}
7 <span class="black-text">{{ form_errors(form.term) }}</span>
8 {% endif %}
9
10 <input type="hidden" name="currentRoute" value="{{ currentRoute }}" />
11
12 {{ form_widget(form.term, { 'attr': {'autocomplete': 'off', 'placeholder': 'entry.search.placeholder'} }) }}
13
14 {{ form_rest(form) }}
15</form>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/new_form.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/new_form.html.twig
index 6e552560..b702c4b6 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/new_form.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Tag/new_form.html.twig
@@ -9,5 +9,6 @@
9 9
10 {{ form_widget(form.label, { 'attr': {'autocomplete': 'off'} }) }} 10 {{ form_widget(form.label, { 'attr': {'autocomplete': 'off'} }) }}
11 11
12 {{ form_rest(form) }} 12 {{ form_widget(form.add, {'attr': {'class': 'btn waves-effect waves-light hide-on-large-only'}}) }}
13 {{ form_widget(form._token) }}
13</form> 14</form>
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
index f1ef01df..e5bfc62c 100644
--- a/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
@@ -89,11 +89,11 @@
89 <i class="material-icons">add</i> 89 <i class="material-icons">add</i>
90 </a> 90 </a>
91 </li> 91 </li>
92 <!--<li> 92 <li>
93 <a title="{{ 'menu.top.search'|trans }}" class="waves-effect" href="javascript: void(null);" id="nav-btn-search"> 93 <a class="waves-effect tooltipped" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.search'|trans }}" href="javascript: void(null);" id="nav-btn-search">
94 <i class="material-icons">search</i> 94 <i class="material-icons">search</i>
95 </a> 95 </a>
96 </li>--> 96 </li>
97 <li id="button_filters"> 97 <li id="button_filters">
98 <a class="nav-panel-menu button-collapse-right tooltipped" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.filter_entries'|trans }}" href="#" data-activates="filters"> 98 <a class="nav-panel-menu button-collapse-right tooltipped" data-position="bottom" data-delay="50" data-tooltip="{{ 'menu.top.filter_entries'|trans }}" href="#" data-activates="filters">
99 <i class="material-icons">filter_list</i> 99 <i class="material-icons">filter_list</i>
@@ -106,13 +106,11 @@
106 </li> 106 </li>
107 </ul> 107 </ul>
108 </div> 108 </div>
109 <form method="get" action="index.php"> 109 <div class="input-field nav-panel-search" style="display: none">
110 <div class="input-field nav-panel-search" style="display: none"> 110 {{ render(controller("WallabagCoreBundle:Entry:searchForm", {'currentRoute': app.request.attributes.get('_route')})) }}
111 <input name="search" id="searchfield" type="search" required placeholder="{{ 'menu.search_form.input_label'|trans }}"> 111 <label for="search" class="active"><i class="material-icons search">search</i></label>
112 <label for="search"><i class="material-icons search">search</i></label> 112 <i class="material-icons close">clear</i>
113 <i class="material-icons close">clear</i> 113 </div>
114 </div>
115 </form>
116 <div class="input-field nav-panel-add" style="display: none"> 114 <div class="input-field nav-panel-add" style="display: none">
117 {{ render(controller("WallabagCoreBundle:Entry:addEntryForm")) }} 115 {{ render(controller("WallabagCoreBundle:Entry:addEntryForm")) }}
118 <label for="add" class="active"><i class="material-icons add">add</i></label> 116 <label for="add" class="active"><i class="material-icons add">add</i></label>
diff --git a/src/Wallabag/ImportBundle/Command/ImportCommand.php b/src/Wallabag/ImportBundle/Command/ImportCommand.php
index d1325338..28d01715 100644
--- a/src/Wallabag/ImportBundle/Command/ImportCommand.php
+++ b/src/Wallabag/ImportBundle/Command/ImportCommand.php
@@ -14,10 +14,10 @@ class ImportCommand extends ContainerAwareCommand
14 { 14 {
15 $this 15 $this
16 ->setName('wallabag:import') 16 ->setName('wallabag:import')
17 ->setDescription('Import entries from a JSON export from a wallabag v1 instance') 17 ->setDescription('Import entries from a JSON export')
18 ->addArgument('userId', InputArgument::REQUIRED, 'User ID to populate') 18 ->addArgument('userId', InputArgument::REQUIRED, 'User ID to populate')
19 ->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file') 19 ->addArgument('filepath', InputArgument::REQUIRED, 'Path to the JSON file')
20 ->addOption('importer', null, InputArgument::OPTIONAL, 'The importer to use: wallabag v1, v2, firefox or chrome', 'v1') 20 ->addOption('importer', null, InputArgument::OPTIONAL, 'The importer to use: v1, v2, instapaper, pinboard, readability, firefox or chrome', 'v1')
21 ->addOption('markAsRead', null, InputArgument::OPTIONAL, 'Mark all entries as read', false) 21 ->addOption('markAsRead', null, InputArgument::OPTIONAL, 'Mark all entries as read', false)
22 ; 22 ;
23 } 23 }
@@ -42,32 +42,36 @@ class ImportCommand extends ContainerAwareCommand
42 42
43 switch ($input->getOption('importer')) { 43 switch ($input->getOption('importer')) {
44 case 'v2': 44 case 'v2':
45 $wallabag = $this->getContainer()->get('wallabag_import.wallabag_v2.import'); 45 $import = $this->getContainer()->get('wallabag_import.wallabag_v2.import');
46 break; 46 break;
47 case 'firefox': 47 case 'firefox':
48 $wallabag = $this->getContainer()->get('wallabag_import.firefox.import'); 48 $import = $this->getContainer()->get('wallabag_import.firefox.import');
49 break; 49 break;
50 case 'chrome': 50 case 'chrome':
51 $wallabag = $this->getContainer()->get('wallabag_import.chrome.import'); 51 $import = $this->getContainer()->get('wallabag_import.chrome.import');
52 break;
53 case 'readability':
54 $import = $this->getContainer()->get('wallabag_import.readability.import');
52 break; 55 break;
53 case 'instapaper': 56 case 'instapaper':
54 $wallabag = $this->getContainer()->get('wallabag_import.instapaper.import'); 57 $import = $this->getContainer()->get('wallabag_import.instapaper.import');
55 break; 58 break;
56 case 'v1': 59 case 'pinboard':
57 default: 60 $import = $this->getContainer()->get('wallabag_import.pinboard.import');
58 $wallabag = $this->getContainer()->get('wallabag_import.wallabag_v1.import');
59 break; 61 break;
62 default:
63 $import = $this->getContainer()->get('wallabag_import.wallabag_v1.import');
60 } 64 }
61 65
62 $wallabag->setMarkAsRead($input->getOption('markAsRead')); 66 $import->setMarkAsRead($input->getOption('markAsRead'));
63 $wallabag->setUser($user); 67 $import->setUser($user);
64 68
65 $res = $wallabag 69 $res = $import
66 ->setFilepath($input->getArgument('filepath')) 70 ->setFilepath($input->getArgument('filepath'))
67 ->import(); 71 ->import();
68 72
69 if (true === $res) { 73 if (true === $res) {
70 $summary = $wallabag->getSummary(); 74 $summary = $import->getSummary();
71 $output->writeln('<info>'.$summary['imported'].' imported</info>'); 75 $output->writeln('<info>'.$summary['imported'].' imported</info>');
72 $output->writeln('<comment>'.$summary['skipped'].' already saved</comment>'); 76 $output->writeln('<comment>'.$summary['skipped'].' already saved</comment>');
73 } 77 }
diff --git a/src/Wallabag/ImportBundle/Command/RedisWorkerCommand.php b/src/Wallabag/ImportBundle/Command/RedisWorkerCommand.php
index c2c11f11..f793a314 100644
--- a/src/Wallabag/ImportBundle/Command/RedisWorkerCommand.php
+++ b/src/Wallabag/ImportBundle/Command/RedisWorkerCommand.php
@@ -17,7 +17,7 @@ class RedisWorkerCommand extends ContainerAwareCommand
17 $this 17 $this
18 ->setName('wallabag:import:redis-worker') 18 ->setName('wallabag:import:redis-worker')
19 ->setDescription('Launch Redis worker') 19 ->setDescription('Launch Redis worker')
20 ->addArgument('serviceName', InputArgument::REQUIRED, 'Service to use: wallabag_v1, wallabag_v2, pocket, readability, firefox, chrome or instapaper') 20 ->addArgument('serviceName', InputArgument::REQUIRED, 'Service to use: wallabag_v1, wallabag_v2, pocket, readability, pinboard, firefox, chrome or instapaper')
21 ->addOption('maxIterations', '', InputOption::VALUE_OPTIONAL, 'Number of iterations before stoping', false) 21 ->addOption('maxIterations', '', InputOption::VALUE_OPTIONAL, 'Number of iterations before stoping', false)
22 ; 22 ;
23 } 23 }
diff --git a/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php b/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php
index b893ea29..fc175f67 100644
--- a/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php
+++ b/src/Wallabag/ImportBundle/Consumer/AbstractConsumer.php
@@ -9,19 +9,23 @@ use Wallabag\CoreBundle\Entity\Entry;
9use Wallabag\CoreBundle\Entity\Tag; 9use Wallabag\CoreBundle\Entity\Tag;
10use Psr\Log\LoggerInterface; 10use Psr\Log\LoggerInterface;
11use Psr\Log\NullLogger; 11use Psr\Log\NullLogger;
12use Symfony\Component\EventDispatcher\EventDispatcherInterface;
13use Wallabag\CoreBundle\Event\EntrySavedEvent;
12 14
13abstract class AbstractConsumer 15abstract class AbstractConsumer
14{ 16{
15 protected $em; 17 protected $em;
16 protected $userRepository; 18 protected $userRepository;
17 protected $import; 19 protected $import;
20 protected $eventDispatcher;
18 protected $logger; 21 protected $logger;
19 22
20 public function __construct(EntityManager $em, UserRepository $userRepository, AbstractImport $import, LoggerInterface $logger = null) 23 public function __construct(EntityManager $em, UserRepository $userRepository, AbstractImport $import, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger = null)
21 { 24 {
22 $this->em = $em; 25 $this->em = $em;
23 $this->userRepository = $userRepository; 26 $this->userRepository = $userRepository;
24 $this->import = $import; 27 $this->import = $import;
28 $this->eventDispatcher = $eventDispatcher;
25 $this->logger = $logger ?: new NullLogger(); 29 $this->logger = $logger ?: new NullLogger();
26 } 30 }
27 31
@@ -59,6 +63,9 @@ abstract class AbstractConsumer
59 try { 63 try {
60 $this->em->flush(); 64 $this->em->flush();
61 65
66 // entry saved, dispatch event about it!
67 $this->eventDispatcher->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
68
62 // clear only affected entities 69 // clear only affected entities
63 $this->em->clear(Entry::class); 70 $this->em->clear(Entry::class);
64 $this->em->clear(Tag::class); 71 $this->em->clear(Tag::class);
diff --git a/src/Wallabag/ImportBundle/Controller/ImportController.php b/src/Wallabag/ImportBundle/Controller/ImportController.php
index 15de75ff..237c748e 100644
--- a/src/Wallabag/ImportBundle/Controller/ImportController.php
+++ b/src/Wallabag/ImportBundle/Controller/ImportController.php
@@ -42,6 +42,7 @@ class ImportController extends Controller
42 + $this->getTotalMessageInRabbitQueue('firefox') 42 + $this->getTotalMessageInRabbitQueue('firefox')
43 + $this->getTotalMessageInRabbitQueue('chrome') 43 + $this->getTotalMessageInRabbitQueue('chrome')
44 + $this->getTotalMessageInRabbitQueue('instapaper') 44 + $this->getTotalMessageInRabbitQueue('instapaper')
45 + $this->getTotalMessageInRabbitQueue('pinboard')
45 ; 46 ;
46 } catch (\Exception $e) { 47 } catch (\Exception $e) {
47 $rabbitNotInstalled = true; 48 $rabbitNotInstalled = true;
@@ -57,6 +58,7 @@ class ImportController extends Controller
57 + $redis->llen('wallabag.import.firefox') 58 + $redis->llen('wallabag.import.firefox')
58 + $redis->llen('wallabag.import.chrome') 59 + $redis->llen('wallabag.import.chrome')
59 + $redis->llen('wallabag.import.instapaper') 60 + $redis->llen('wallabag.import.instapaper')
61 + $redis->llen('wallabag.import.pinboard')
60 ; 62 ;
61 } catch (\Exception $e) { 63 } catch (\Exception $e) {
62 $redisNotInstalled = true; 64 $redisNotInstalled = true;
diff --git a/src/Wallabag/ImportBundle/Controller/PinboardController.php b/src/Wallabag/ImportBundle/Controller/PinboardController.php
new file mode 100644
index 00000000..9c3f98d6
--- /dev/null
+++ b/src/Wallabag/ImportBundle/Controller/PinboardController.php
@@ -0,0 +1,77 @@
1<?php
2
3namespace Wallabag\ImportBundle\Controller;
4
5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
6use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
7use Symfony\Component\HttpFoundation\Request;
8use Wallabag\ImportBundle\Form\Type\UploadImportType;
9
10class PinboardController extends Controller
11{
12 /**
13 * @Route("/pinboard", name="import_pinboard")
14 */
15 public function indexAction(Request $request)
16 {
17 $form = $this->createForm(UploadImportType::class);
18 $form->handleRequest($request);
19
20 $pinboard = $this->get('wallabag_import.pinboard.import');
21 $pinboard->setUser($this->getUser());
22
23 if ($this->get('craue_config')->get('import_with_rabbitmq')) {
24 $pinboard->setProducer($this->get('old_sound_rabbit_mq.import_pinboard_producer'));
25 } elseif ($this->get('craue_config')->get('import_with_redis')) {
26 $pinboard->setProducer($this->get('wallabag_import.producer.redis.pinboard'));
27 }
28
29 if ($form->isValid()) {
30 $file = $form->get('file')->getData();
31 $markAsRead = $form->get('mark_as_read')->getData();
32 $name = 'pinboard_'.$this->getUser()->getId().'.json';
33
34 if (null !== $file && in_array($file->getClientMimeType(), $this->getParameter('wallabag_import.allow_mimetypes')) && $file->move($this->getParameter('wallabag_import.resource_dir'), $name)) {
35 $res = $pinboard
36 ->setFilepath($this->getParameter('wallabag_import.resource_dir').'/'.$name)
37 ->setMarkAsRead($markAsRead)
38 ->import();
39
40 $message = 'flashes.import.notice.failed';
41
42 if (true === $res) {
43 $summary = $pinboard->getSummary();
44 $message = $this->get('translator')->trans('flashes.import.notice.summary', [
45 '%imported%' => $summary['imported'],
46 '%skipped%' => $summary['skipped'],
47 ]);
48
49 if (0 < $summary['queued']) {
50 $message = $this->get('translator')->trans('flashes.import.notice.summary_with_queue', [
51 '%queued%' => $summary['queued'],
52 ]);
53 }
54
55 unlink($this->getParameter('wallabag_import.resource_dir').'/'.$name);
56 }
57
58 $this->get('session')->getFlashBag()->add(
59 'notice',
60 $message
61 );
62
63 return $this->redirect($this->generateUrl('homepage'));
64 } else {
65 $this->get('session')->getFlashBag()->add(
66 'notice',
67 'flashes.import.notice.failed_on_file'
68 );
69 }
70 }
71
72 return $this->render('WallabagImportBundle:Pinboard:index.html.twig', [
73 'form' => $form->createView(),
74 'import' => $pinboard,
75 ]);
76 }
77}
diff --git a/src/Wallabag/ImportBundle/Import/AbstractImport.php b/src/Wallabag/ImportBundle/Import/AbstractImport.php
index 764b390a..1d4a6e27 100644
--- a/src/Wallabag/ImportBundle/Import/AbstractImport.php
+++ b/src/Wallabag/ImportBundle/Import/AbstractImport.php
@@ -10,12 +10,15 @@ use Wallabag\CoreBundle\Entity\Entry;
10use Wallabag\CoreBundle\Entity\Tag; 10use Wallabag\CoreBundle\Entity\Tag;
11use Wallabag\UserBundle\Entity\User; 11use Wallabag\UserBundle\Entity\User;
12use OldSound\RabbitMqBundle\RabbitMq\ProducerInterface; 12use OldSound\RabbitMqBundle\RabbitMq\ProducerInterface;
13use Symfony\Component\EventDispatcher\EventDispatcherInterface;
14use Wallabag\CoreBundle\Event\EntrySavedEvent;
13 15
14abstract class AbstractImport implements ImportInterface 16abstract class AbstractImport implements ImportInterface
15{ 17{
16 protected $em; 18 protected $em;
17 protected $logger; 19 protected $logger;
18 protected $contentProxy; 20 protected $contentProxy;
21 protected $eventDispatcher;
19 protected $producer; 22 protected $producer;
20 protected $user; 23 protected $user;
21 protected $markAsRead; 24 protected $markAsRead;
@@ -23,11 +26,12 @@ abstract class AbstractImport implements ImportInterface
23 protected $importedEntries = 0; 26 protected $importedEntries = 0;
24 protected $queuedEntries = 0; 27 protected $queuedEntries = 0;
25 28
26 public function __construct(EntityManager $em, ContentProxy $contentProxy) 29 public function __construct(EntityManager $em, ContentProxy $contentProxy, EventDispatcherInterface $eventDispatcher)
27 { 30 {
28 $this->em = $em; 31 $this->em = $em;
29 $this->logger = new NullLogger(); 32 $this->logger = new NullLogger();
30 $this->contentProxy = $contentProxy; 33 $this->contentProxy = $contentProxy;
34 $this->eventDispatcher = $eventDispatcher;
31 } 35 }
32 36
33 public function setLogger(LoggerInterface $logger) 37 public function setLogger(LoggerInterface $logger)
@@ -104,6 +108,7 @@ abstract class AbstractImport implements ImportInterface
104 protected function parseEntries($entries) 108 protected function parseEntries($entries)
105 { 109 {
106 $i = 1; 110 $i = 1;
111 $entryToBeFlushed = [];
107 112
108 foreach ($entries as $importedEntry) { 113 foreach ($entries as $importedEntry) {
109 if ($this->markAsRead) { 114 if ($this->markAsRead) {
@@ -116,10 +121,21 @@ abstract class AbstractImport implements ImportInterface
116 continue; 121 continue;
117 } 122 }
118 123
124 // store each entry to be flushed so we can trigger the entry.saved event for each of them
125 // entry.saved needs the entry to be persisted in db because it needs it id to generate
126 // images (at least)
127 $entryToBeFlushed[] = $entry;
128
119 // flush every 20 entries 129 // flush every 20 entries
120 if (($i % 20) === 0) { 130 if (($i % 20) === 0) {
121 $this->em->flush(); 131 $this->em->flush();
122 132
133 foreach ($entryToBeFlushed as $entry) {
134 $this->eventDispatcher->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
135 }
136
137 $entryToBeFlushed = [];
138
123 // clear only affected entities 139 // clear only affected entities
124 $this->em->clear(Entry::class); 140 $this->em->clear(Entry::class);
125 $this->em->clear(Tag::class); 141 $this->em->clear(Tag::class);
@@ -128,6 +144,12 @@ abstract class AbstractImport implements ImportInterface
128 } 144 }
129 145
130 $this->em->flush(); 146 $this->em->flush();
147
148 if (!empty($entryToBeFlushed)) {
149 foreach ($entryToBeFlushed as $entry) {
150 $this->eventDispatcher->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
151 }
152 }
131 } 153 }
132 154
133 /** 155 /**
diff --git a/src/Wallabag/ImportBundle/Import/BrowserImport.php b/src/Wallabag/ImportBundle/Import/BrowserImport.php
index 2ca1683b..8bf7d92e 100644
--- a/src/Wallabag/ImportBundle/Import/BrowserImport.php
+++ b/src/Wallabag/ImportBundle/Import/BrowserImport.php
@@ -5,6 +5,7 @@ namespace Wallabag\ImportBundle\Import;
5use Wallabag\CoreBundle\Entity\Entry; 5use Wallabag\CoreBundle\Entity\Entry;
6use Wallabag\UserBundle\Entity\User; 6use Wallabag\UserBundle\Entity\User;
7use Wallabag\CoreBundle\Helper\ContentProxy; 7use Wallabag\CoreBundle\Helper\ContentProxy;
8use Wallabag\CoreBundle\Event\EntrySavedEvent;
8 9
9abstract class BrowserImport extends AbstractImport 10abstract class BrowserImport extends AbstractImport
10{ 11{
@@ -81,6 +82,7 @@ abstract class BrowserImport extends AbstractImport
81 protected function parseEntries($entries) 82 protected function parseEntries($entries)
82 { 83 {
83 $i = 1; 84 $i = 1;
85 $entryToBeFlushed = [];
84 86
85 foreach ($entries as $importedEntry) { 87 foreach ($entries as $importedEntry) {
86 if ((array) $importedEntry !== $importedEntry) { 88 if ((array) $importedEntry !== $importedEntry) {
@@ -93,14 +95,29 @@ abstract class BrowserImport extends AbstractImport
93 continue; 95 continue;
94 } 96 }
95 97
98 // @see AbstractImport
99 $entryToBeFlushed[] = $entry;
100
96 // flush every 20 entries 101 // flush every 20 entries
97 if (($i % 20) === 0) { 102 if (($i % 20) === 0) {
98 $this->em->flush(); 103 $this->em->flush();
104
105 foreach ($entryToBeFlushed as $entry) {
106 $this->eventDispatcher->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
107 }
108
109 $entryToBeFlushed = [];
99 } 110 }
100 ++$i; 111 ++$i;
101 } 112 }
102 113
103 $this->em->flush(); 114 $this->em->flush();
115
116 if (!empty($entryToBeFlushed)) {
117 foreach ($entryToBeFlushed as $entry) {
118 $this->eventDispatcher->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry));
119 }
120 }
104 } 121 }
105 122
106 /** 123 /**
diff --git a/src/Wallabag/ImportBundle/Import/PinboardImport.php b/src/Wallabag/ImportBundle/Import/PinboardImport.php
new file mode 100644
index 00000000..9bcfbc36
--- /dev/null
+++ b/src/Wallabag/ImportBundle/Import/PinboardImport.php
@@ -0,0 +1,143 @@
1<?php
2
3namespace Wallabag\ImportBundle\Import;
4
5use Wallabag\CoreBundle\Entity\Entry;
6
7class PinboardImport extends AbstractImport
8{
9 private $filepath;
10
11 /**
12 * {@inheritdoc}
13 */
14 public function getName()
15 {
16 return 'Pinboard';
17 }
18
19 /**
20 * {@inheritdoc}
21 */
22 public function getUrl()
23 {
24 return 'import_pinboard';
25 }
26
27 /**
28 * {@inheritdoc}
29 */
30 public function getDescription()
31 {
32 return 'import.pinboard.description';
33 }
34
35 /**
36 * Set file path to the json file.
37 *
38 * @param string $filepath
39 */
40 public function setFilepath($filepath)
41 {
42 $this->filepath = $filepath;
43
44 return $this;
45 }
46
47 /**
48 * {@inheritdoc}
49 */
50 public function import()
51 {
52 if (!$this->user) {
53 $this->logger->error('PinboardImport: user is not defined');
54
55 return false;
56 }
57
58 if (!file_exists($this->filepath) || !is_readable($this->filepath)) {
59 $this->logger->error('PinboardImport: unable to read file', ['filepath' => $this->filepath]);
60
61 return false;
62 }
63
64 $data = json_decode(file_get_contents($this->filepath), true);
65
66 if (empty($data)) {
67 $this->logger->error('PinboardImport: no entries in imported file');
68
69 return false;
70 }
71
72 if ($this->producer) {
73 $this->parseEntriesForProducer($data);
74
75 return true;
76 }
77
78 $this->parseEntries($data);
79
80 return true;
81 }
82
83 /**
84 * {@inheritdoc}
85 */
86 public function parseEntry(array $importedEntry)
87 {
88 $existingEntry = $this->em
89 ->getRepository('WallabagCoreBundle:Entry')
90 ->findByUrlAndUserId($importedEntry['href'], $this->user->getId());
91
92 if (false !== $existingEntry) {
93 ++$this->skippedEntries;
94
95 return;
96 }
97
98 $data = [
99 'title' => $importedEntry['description'],
100 'url' => $importedEntry['href'],
101 'content_type' => '',
102 'language' => '',
103 'is_archived' => ('no' === $importedEntry['toread']) || $this->markAsRead,
104 'is_starred' => false,
105 'created_at' => $importedEntry['time'],
106 'tags' => explode(' ', $importedEntry['tags']),
107 ];
108
109 $entry = new Entry($this->user);
110 $entry->setUrl($data['url']);
111 $entry->setTitle($data['title']);
112
113 // update entry with content (in case fetching failed, the given entry will be return)
114 $entry = $this->fetchContent($entry, $data['url'], $data);
115
116 if (!empty($data['tags'])) {
117 $this->contentProxy->assignTagsToEntry(
118 $entry,
119 $data['tags'],
120 $this->em->getUnitOfWork()->getScheduledEntityInsertions()
121 );
122 }
123
124 $entry->setArchived($data['is_archived']);
125 $entry->setStarred($data['is_starred']);
126 $entry->setCreatedAt(new \DateTime($data['created_at']));
127
128 $this->em->persist($entry);
129 ++$this->importedEntries;
130
131 return $entry;
132 }
133
134 /**
135 * {@inheritdoc}
136 */
137 protected function setEntryAsRead(array $importedEntry)
138 {
139 $importedEntry['toread'] = 'no';
140
141 return $importedEntry;
142 }
143}
diff --git a/src/Wallabag/ImportBundle/Import/PocketImport.php b/src/Wallabag/ImportBundle/Import/PocketImport.php
index 327e2500..33093480 100644
--- a/src/Wallabag/ImportBundle/Import/PocketImport.php
+++ b/src/Wallabag/ImportBundle/Import/PocketImport.php
@@ -2,8 +2,6 @@
2 2
3namespace Wallabag\ImportBundle\Import; 3namespace Wallabag\ImportBundle\Import;
4 4
5use Psr\Log\NullLogger;
6use Doctrine\ORM\EntityManager;
7use GuzzleHttp\Client; 5use GuzzleHttp\Client;
8use GuzzleHttp\Exception\RequestException; 6use GuzzleHttp\Exception\RequestException;
9use Wallabag\CoreBundle\Entity\Entry; 7use Wallabag\CoreBundle\Entity\Entry;
@@ -16,13 +14,6 @@ class PocketImport extends AbstractImport
16 14
17 const NB_ELEMENTS = 5000; 15 const NB_ELEMENTS = 5000;
18 16
19 public function __construct(EntityManager $em, ContentProxy $contentProxy)
20 {
21 $this->em = $em;
22 $this->contentProxy = $contentProxy;
23 $this->logger = new NullLogger();
24 }
25
26 /** 17 /**
27 * Only used for test purpose. 18 * Only used for test purpose.
28 * 19 *
diff --git a/src/Wallabag/ImportBundle/Resources/config/rabbit.yml b/src/Wallabag/ImportBundle/Resources/config/rabbit.yml
index 70b8a0d4..e9ecb846 100644
--- a/src/Wallabag/ImportBundle/Resources/config/rabbit.yml
+++ b/src/Wallabag/ImportBundle/Resources/config/rabbit.yml
@@ -6,6 +6,7 @@ services:
6 - "@doctrine.orm.entity_manager" 6 - "@doctrine.orm.entity_manager"
7 - "@wallabag_user.user_repository" 7 - "@wallabag_user.user_repository"
8 - "@wallabag_import.pocket.import" 8 - "@wallabag_import.pocket.import"
9 - "@event_dispatcher"
9 - "@logger" 10 - "@logger"
10 wallabag_import.consumer.amqp.readability: 11 wallabag_import.consumer.amqp.readability:
11 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer 12 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer
@@ -13,6 +14,7 @@ services:
13 - "@doctrine.orm.entity_manager" 14 - "@doctrine.orm.entity_manager"
14 - "@wallabag_user.user_repository" 15 - "@wallabag_user.user_repository"
15 - "@wallabag_import.readability.import" 16 - "@wallabag_import.readability.import"
17 - "@event_dispatcher"
16 - "@logger" 18 - "@logger"
17 wallabag_import.consumer.amqp.instapaper: 19 wallabag_import.consumer.amqp.instapaper:
18 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer 20 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer
@@ -20,6 +22,15 @@ services:
20 - "@doctrine.orm.entity_manager" 22 - "@doctrine.orm.entity_manager"
21 - "@wallabag_user.user_repository" 23 - "@wallabag_user.user_repository"
22 - "@wallabag_import.instapaper.import" 24 - "@wallabag_import.instapaper.import"
25 - "@event_dispatcher"
26 - "@logger"
27 wallabag_import.consumer.amqp.pinboard:
28 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer
29 arguments:
30 - "@doctrine.orm.entity_manager"
31 - "@wallabag_user.user_repository"
32 - "@wallabag_import.pinboard.import"
33 - "@event_dispatcher"
23 - "@logger" 34 - "@logger"
24 wallabag_import.consumer.amqp.wallabag_v1: 35 wallabag_import.consumer.amqp.wallabag_v1:
25 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer 36 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer
@@ -27,6 +38,7 @@ services:
27 - "@doctrine.orm.entity_manager" 38 - "@doctrine.orm.entity_manager"
28 - "@wallabag_user.user_repository" 39 - "@wallabag_user.user_repository"
29 - "@wallabag_import.wallabag_v1.import" 40 - "@wallabag_import.wallabag_v1.import"
41 - "@event_dispatcher"
30 - "@logger" 42 - "@logger"
31 wallabag_import.consumer.amqp.wallabag_v2: 43 wallabag_import.consumer.amqp.wallabag_v2:
32 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer 44 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer
@@ -34,6 +46,7 @@ services:
34 - "@doctrine.orm.entity_manager" 46 - "@doctrine.orm.entity_manager"
35 - "@wallabag_user.user_repository" 47 - "@wallabag_user.user_repository"
36 - "@wallabag_import.wallabag_v2.import" 48 - "@wallabag_import.wallabag_v2.import"
49 - "@event_dispatcher"
37 - "@logger" 50 - "@logger"
38 wallabag_import.consumer.amqp.firefox: 51 wallabag_import.consumer.amqp.firefox:
39 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer 52 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer
@@ -41,6 +54,7 @@ services:
41 - "@doctrine.orm.entity_manager" 54 - "@doctrine.orm.entity_manager"
42 - "@wallabag_user.user_repository" 55 - "@wallabag_user.user_repository"
43 - "@wallabag_import.firefox.import" 56 - "@wallabag_import.firefox.import"
57 - "@event_dispatcher"
44 - "@logger" 58 - "@logger"
45 wallabag_import.consumer.amqp.chrome: 59 wallabag_import.consumer.amqp.chrome:
46 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer 60 class: Wallabag\ImportBundle\Consumer\AMQPEntryConsumer
@@ -48,4 +62,5 @@ services:
48 - "@doctrine.orm.entity_manager" 62 - "@doctrine.orm.entity_manager"
49 - "@wallabag_user.user_repository" 63 - "@wallabag_user.user_repository"
50 - "@wallabag_import.chrome.import" 64 - "@wallabag_import.chrome.import"
65 - "@event_dispatcher"
51 - "@logger" 66 - "@logger"
diff --git a/src/Wallabag/ImportBundle/Resources/config/redis.yml b/src/Wallabag/ImportBundle/Resources/config/redis.yml
index 0a81e1b5..091cdba0 100644
--- a/src/Wallabag/ImportBundle/Resources/config/redis.yml
+++ b/src/Wallabag/ImportBundle/Resources/config/redis.yml
@@ -18,6 +18,7 @@ services:
18 - "@doctrine.orm.entity_manager" 18 - "@doctrine.orm.entity_manager"
19 - "@wallabag_user.user_repository" 19 - "@wallabag_user.user_repository"
20 - "@wallabag_import.readability.import" 20 - "@wallabag_import.readability.import"
21 - "@event_dispatcher"
21 - "@logger" 22 - "@logger"
22 23
23 # instapaper 24 # instapaper
@@ -38,6 +39,28 @@ services:
38 - "@doctrine.orm.entity_manager" 39 - "@doctrine.orm.entity_manager"
39 - "@wallabag_user.user_repository" 40 - "@wallabag_user.user_repository"
40 - "@wallabag_import.instapaper.import" 41 - "@wallabag_import.instapaper.import"
42 - "@event_dispatcher"
43 - "@logger"
44
45 # pinboard
46 wallabag_import.queue.redis.pinboard:
47 class: Simpleue\Queue\RedisQueue
48 arguments:
49 - "@wallabag_core.redis.client"
50 - "wallabag.import.pinboard"
51
52 wallabag_import.producer.redis.pinboard:
53 class: Wallabag\ImportBundle\Redis\Producer
54 arguments:
55 - "@wallabag_import.queue.redis.pinboard"
56
57 wallabag_import.consumer.redis.pinboard:
58 class: Wallabag\ImportBundle\Consumer\RedisEntryConsumer
59 arguments:
60 - "@doctrine.orm.entity_manager"
61 - "@wallabag_user.user_repository"
62 - "@wallabag_import.pinboard.import"
63 - "@event_dispatcher"
41 - "@logger" 64 - "@logger"
42 65
43 # pocket 66 # pocket
@@ -58,6 +81,7 @@ services:
58 - "@doctrine.orm.entity_manager" 81 - "@doctrine.orm.entity_manager"
59 - "@wallabag_user.user_repository" 82 - "@wallabag_user.user_repository"
60 - "@wallabag_import.pocket.import" 83 - "@wallabag_import.pocket.import"
84 - "@event_dispatcher"
61 - "@logger" 85 - "@logger"
62 86
63 # wallabag v1 87 # wallabag v1
@@ -78,6 +102,7 @@ services:
78 - "@doctrine.orm.entity_manager" 102 - "@doctrine.orm.entity_manager"
79 - "@wallabag_user.user_repository" 103 - "@wallabag_user.user_repository"
80 - "@wallabag_import.wallabag_v1.import" 104 - "@wallabag_import.wallabag_v1.import"
105 - "@event_dispatcher"
81 - "@logger" 106 - "@logger"
82 107
83 # wallabag v2 108 # wallabag v2
@@ -98,6 +123,7 @@ services:
98 - "@doctrine.orm.entity_manager" 123 - "@doctrine.orm.entity_manager"
99 - "@wallabag_user.user_repository" 124 - "@wallabag_user.user_repository"
100 - "@wallabag_import.wallabag_v2.import" 125 - "@wallabag_import.wallabag_v2.import"
126 - "@event_dispatcher"
101 - "@logger" 127 - "@logger"
102 128
103 # firefox 129 # firefox
@@ -118,6 +144,7 @@ services:
118 - "@doctrine.orm.entity_manager" 144 - "@doctrine.orm.entity_manager"
119 - "@wallabag_user.user_repository" 145 - "@wallabag_user.user_repository"
120 - "@wallabag_import.firefox.import" 146 - "@wallabag_import.firefox.import"
147 - "@event_dispatcher"
121 - "@logger" 148 - "@logger"
122 149
123 # chrome 150 # chrome
@@ -138,4 +165,5 @@ services:
138 - "@doctrine.orm.entity_manager" 165 - "@doctrine.orm.entity_manager"
139 - "@wallabag_user.user_repository" 166 - "@wallabag_user.user_repository"
140 - "@wallabag_import.chrome.import" 167 - "@wallabag_import.chrome.import"
168 - "@event_dispatcher"
141 - "@logger" 169 - "@logger"
diff --git a/src/Wallabag/ImportBundle/Resources/config/services.yml b/src/Wallabag/ImportBundle/Resources/config/services.yml
index d600be0f..c4fe3f92 100644
--- a/src/Wallabag/ImportBundle/Resources/config/services.yml
+++ b/src/Wallabag/ImportBundle/Resources/config/services.yml
@@ -20,6 +20,7 @@ services:
20 arguments: 20 arguments:
21 - "@doctrine.orm.entity_manager" 21 - "@doctrine.orm.entity_manager"
22 - "@wallabag_core.content_proxy" 22 - "@wallabag_core.content_proxy"
23 - "@event_dispatcher"
23 calls: 24 calls:
24 - [ setClient, [ "@wallabag_import.pocket.client" ] ] 25 - [ setClient, [ "@wallabag_import.pocket.client" ] ]
25 - [ setLogger, [ "@logger" ]] 26 - [ setLogger, [ "@logger" ]]
@@ -31,6 +32,7 @@ services:
31 arguments: 32 arguments:
32 - "@doctrine.orm.entity_manager" 33 - "@doctrine.orm.entity_manager"
33 - "@wallabag_core.content_proxy" 34 - "@wallabag_core.content_proxy"
35 - "@event_dispatcher"
34 calls: 36 calls:
35 - [ setLogger, [ "@logger" ]] 37 - [ setLogger, [ "@logger" ]]
36 tags: 38 tags:
@@ -41,6 +43,7 @@ services:
41 arguments: 43 arguments:
42 - "@doctrine.orm.entity_manager" 44 - "@doctrine.orm.entity_manager"
43 - "@wallabag_core.content_proxy" 45 - "@wallabag_core.content_proxy"
46 - "@event_dispatcher"
44 calls: 47 calls:
45 - [ setLogger, [ "@logger" ]] 48 - [ setLogger, [ "@logger" ]]
46 tags: 49 tags:
@@ -51,6 +54,7 @@ services:
51 arguments: 54 arguments:
52 - "@doctrine.orm.entity_manager" 55 - "@doctrine.orm.entity_manager"
53 - "@wallabag_core.content_proxy" 56 - "@wallabag_core.content_proxy"
57 - "@event_dispatcher"
54 calls: 58 calls:
55 - [ setLogger, [ "@logger" ]] 59 - [ setLogger, [ "@logger" ]]
56 tags: 60 tags:
@@ -61,16 +65,29 @@ services:
61 arguments: 65 arguments:
62 - "@doctrine.orm.entity_manager" 66 - "@doctrine.orm.entity_manager"
63 - "@wallabag_core.content_proxy" 67 - "@wallabag_core.content_proxy"
68 - "@event_dispatcher"
64 calls: 69 calls:
65 - [ setLogger, [ "@logger" ]] 70 - [ setLogger, [ "@logger" ]]
66 tags: 71 tags:
67 - { name: wallabag_import.import, alias: instapaper } 72 - { name: wallabag_import.import, alias: instapaper }
68 73
74 wallabag_import.pinboard.import:
75 class: Wallabag\ImportBundle\Import\PinboardImport
76 arguments:
77 - "@doctrine.orm.entity_manager"
78 - "@wallabag_core.content_proxy"
79 - "@event_dispatcher"
80 calls:
81 - [ setLogger, [ "@logger" ]]
82 tags:
83 - { name: wallabag_import.import, alias: pinboard }
84
69 wallabag_import.firefox.import: 85 wallabag_import.firefox.import:
70 class: Wallabag\ImportBundle\Import\FirefoxImport 86 class: Wallabag\ImportBundle\Import\FirefoxImport
71 arguments: 87 arguments:
72 - "@doctrine.orm.entity_manager" 88 - "@doctrine.orm.entity_manager"
73 - "@wallabag_core.content_proxy" 89 - "@wallabag_core.content_proxy"
90 - "@event_dispatcher"
74 calls: 91 calls:
75 - [ setLogger, [ "@logger" ]] 92 - [ setLogger, [ "@logger" ]]
76 tags: 93 tags:
@@ -80,6 +97,7 @@ services:
80 arguments: 97 arguments:
81 - "@doctrine.orm.entity_manager" 98 - "@doctrine.orm.entity_manager"
82 - "@wallabag_core.content_proxy" 99 - "@wallabag_core.content_proxy"
100 - "@event_dispatcher"
83 calls: 101 calls:
84 - [ setLogger, [ "@logger" ]] 102 - [ setLogger, [ "@logger" ]]
85 tags: 103 tags:
diff --git a/src/Wallabag/ImportBundle/Resources/views/Chrome/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Chrome/index.html.twig
index ead828c6..93b08540 100644
--- a/src/Wallabag/ImportBundle/Resources/views/Chrome/index.html.twig
+++ b/src/Wallabag/ImportBundle/Resources/views/Chrome/index.html.twig
@@ -6,6 +6,8 @@
6<div class="row"> 6<div class="row">
7 <div class="col s12"> 7 <div class="col s12">
8 <div class="card-panel settings"> 8 <div class="card-panel settings">
9 {% include 'WallabagImportBundle:Import:_information.html.twig' %}
10
9 <div class="row"> 11 <div class="row">
10 <blockquote>{{ import.description|trans|raw }}</blockquote> 12 <blockquote>{{ import.description|trans|raw }}</blockquote>
11 <p>{{ 'import.chrome.how_to'|trans }}</p> 13 <p>{{ 'import.chrome.how_to'|trans }}</p>
diff --git a/src/Wallabag/ImportBundle/Resources/views/Firefox/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Firefox/index.html.twig
index f975da3f..ced3f008 100644
--- a/src/Wallabag/ImportBundle/Resources/views/Firefox/index.html.twig
+++ b/src/Wallabag/ImportBundle/Resources/views/Firefox/index.html.twig
@@ -6,6 +6,8 @@
6<div class="row"> 6<div class="row">
7 <div class="col s12"> 7 <div class="col s12">
8 <div class="card-panel settings"> 8 <div class="card-panel settings">
9 {% include 'WallabagImportBundle:Import:_information.html.twig' %}
10
9 <div class="row"> 11 <div class="row">
10 <blockquote>{{ import.description|trans|raw }}</blockquote> 12 <blockquote>{{ import.description|trans|raw }}</blockquote>
11 <p>{{ 'import.firefox.how_to'|trans }}</p> 13 <p>{{ 'import.firefox.how_to'|trans }}</p>
diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/_workerEnabled.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/_information.html.twig
index 2390a41f..48bbcfe7 100644
--- a/src/Wallabag/ImportBundle/Resources/views/Import/_workerEnabled.html.twig
+++ b/src/Wallabag/ImportBundle/Resources/views/Import/_information.html.twig
@@ -1,8 +1,15 @@
1{% set redis = craue_setting('import_with_redis') %} 1{% set redis = craue_setting('import_with_redis') %}
2{% set rabbit = craue_setting('import_with_rabbitmq') %} 2{% set rabbit = craue_setting('import_with_rabbitmq') %}
3{% set downloadImages = craue_setting('download_images_enabled') %}
3 4
4{% if redis or rabbit %} 5{% if redis or rabbit %}
5 <div class="card-panel yellow darken-1 black-text"> 6 <div class="card-panel yellow darken-1 black-text">
6 {{ 'import.worker.enabled'|trans }} <strong>{% if rabbit %}RabbitMQ{% elseif redis %}Redis{% endif %}</strong> 7 {{ 'import.worker.enabled'|trans }} <strong>{% if rabbit %}RabbitMQ{% elseif redis %}Redis{% endif %}</strong>
7 </div> 8 </div>
8{% endif %} 9{% endif %}
10
11{% if not redis and not rabbit and downloadImages %}
12 <div class="card-panel orange darken-1 black-text">
13 {{ 'import.worker.download_images_warning'|trans|raw }}
14 </div>
15{% endif %}
diff --git a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig
index 6ea5e0f4..b1ec40a6 100644
--- a/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig
+++ b/src/Wallabag/ImportBundle/Resources/views/Import/index.html.twig
@@ -6,6 +6,8 @@
6<div class="row"> 6<div class="row">
7 <div class="col s12"> 7 <div class="col s12">
8 <div class="card-panel settings"> 8 <div class="card-panel settings">
9 {% include 'WallabagImportBundle:Import:_information.html.twig' %}
10
9 {{ 'import.page_description'|trans }} 11 {{ 'import.page_description'|trans }}
10 <ul> 12 <ul>
11 {% for import in imports %} 13 {% for import in imports %}
diff --git a/src/Wallabag/ImportBundle/Resources/views/Instapaper/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Instapaper/index.html.twig
index 5789361f..28165d19 100644
--- a/src/Wallabag/ImportBundle/Resources/views/Instapaper/index.html.twig
+++ b/src/Wallabag/ImportBundle/Resources/views/Instapaper/index.html.twig
@@ -6,7 +6,7 @@
6<div class="row"> 6<div class="row">
7 <div class="col s12"> 7 <div class="col s12">
8 <div class="card-panel settings"> 8 <div class="card-panel settings">
9 {% include 'WallabagImportBundle:Import:_workerEnabled.html.twig' %} 9 {% include 'WallabagImportBundle:Import:_information.html.twig' %}
10 10
11 <div class="row"> 11 <div class="row">
12 <blockquote>{{ import.description|trans }}</blockquote> 12 <blockquote>{{ import.description|trans }}</blockquote>
diff --git a/src/Wallabag/ImportBundle/Resources/views/Pinboard/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Pinboard/index.html.twig
new file mode 100644
index 00000000..43f196ad
--- /dev/null
+++ b/src/Wallabag/ImportBundle/Resources/views/Pinboard/index.html.twig
@@ -0,0 +1,45 @@
1{% extends "WallabagCoreBundle::layout.html.twig" %}
2
3{% block title %}{{ 'import.pinboard.page_title'|trans }}{% endblock %}
4
5{% block content %}
6<div class="row">
7 <div class="col s12">
8 <div class="card-panel settings">
9 {% include 'WallabagImportBundle:Import:_information.html.twig' %}
10
11 <div class="row">
12 <blockquote>{{ import.description|trans }}</blockquote>
13 <p>{{ 'import.pinboard.how_to'|trans }}</p>
14
15 <div class="col s12">
16 {{ form_start(form, {'method': 'POST'}) }}
17 {{ form_errors(form) }}
18 <div class="row">
19 <div class="file-field input-field col s12">
20 {{ form_errors(form.file) }}
21 <div class="btn">
22 <span>{{ form.file.vars.label|trans }}</span>
23 {{ form_widget(form.file) }}
24 </div>
25 <div class="file-path-wrapper">
26 <input class="file-path validate" type="text">
27 </div>
28 </div>
29 <div class="input-field col s6 with-checkbox">
30 <h6>{{ 'import.form.mark_as_read_title'|trans }}</h6>
31 {{ form_widget(form.mark_as_read) }}
32 {{ form_label(form.mark_as_read) }}
33 </div>
34 </div>
35
36 {{ form_widget(form.save, { 'attr': {'class': 'btn waves-effect waves-light'} }) }}
37
38 {{ form_rest(form) }}
39 </form>
40 </div>
41 </div>
42 </div>
43 </div>
44</div>
45{% endblock %}
diff --git a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig
index 6195fa07..536e3d1a 100644
--- a/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig
+++ b/src/Wallabag/ImportBundle/Resources/views/Pocket/index.html.twig
@@ -6,7 +6,7 @@
6<div class="row"> 6<div class="row">
7 <div class="col s12"> 7 <div class="col s12">
8 <div class="card-panel settings"> 8 <div class="card-panel settings">
9 {% include 'WallabagImportBundle:Import:_workerEnabled.html.twig' %} 9 {% include 'WallabagImportBundle:Import:_information.html.twig' %}
10 10
11 {% if not has_consumer_key %} 11 {% if not has_consumer_key %}
12 <div class="card-panel red white-text"> 12 <div class="card-panel red white-text">
diff --git a/src/Wallabag/ImportBundle/Resources/views/Readability/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/Readability/index.html.twig
index 74653b0f..737b0adf 100644
--- a/src/Wallabag/ImportBundle/Resources/views/Readability/index.html.twig
+++ b/src/Wallabag/ImportBundle/Resources/views/Readability/index.html.twig
@@ -6,7 +6,7 @@
6<div class="row"> 6<div class="row">
7 <div class="col s12"> 7 <div class="col s12">
8 <div class="card-panel settings"> 8 <div class="card-panel settings">
9 {% include 'WallabagImportBundle:Import:_workerEnabled.html.twig' %} 9 {% include 'WallabagImportBundle:Import:_information.html.twig' %}
10 10
11 <div class="row"> 11 <div class="row">
12 <blockquote>{{ import.description|trans }}</blockquote> 12 <blockquote>{{ import.description|trans }}</blockquote>
diff --git a/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig b/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig
index 0b19bc34..974b2c73 100644
--- a/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig
+++ b/src/Wallabag/ImportBundle/Resources/views/WallabagV1/index.html.twig
@@ -6,7 +6,7 @@
6<div class="row"> 6<div class="row">
7 <div class="col s12"> 7 <div class="col s12">
8 <div class="card-panel settings"> 8 <div class="card-panel settings">
9 {% include 'WallabagImportBundle:Import:_workerEnabled.html.twig' %} 9 {% include 'WallabagImportBundle:Import:_information.html.twig' %}
10 10
11 <div class="row"> 11 <div class="row">
12 <blockquote>{{ import.description|trans }}</blockquote> 12 <blockquote>{{ import.description|trans }}</blockquote>
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php
index d98ae76a..3a167de7 100644
--- a/src/Wallabag/UserBundle/Entity/User.php
+++ b/src/Wallabag/UserBundle/Entity/User.php
@@ -11,6 +11,7 @@ use JMS\Serializer\Annotation\ExclusionPolicy;
11use JMS\Serializer\Annotation\Expose; 11use JMS\Serializer\Annotation\Expose;
12use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; 12use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
13use Symfony\Component\Security\Core\User\UserInterface; 13use Symfony\Component\Security\Core\User\UserInterface;
14use Wallabag\ApiBundle\Entity\Client;
14use Wallabag\CoreBundle\Entity\Config; 15use Wallabag\CoreBundle\Entity\Config;
15use Wallabag\CoreBundle\Entity\Entry; 16use Wallabag\CoreBundle\Entity\Entry;
16 17
@@ -84,6 +85,11 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
84 */ 85 */
85 private $trusted; 86 private $trusted;
86 87
88 /**
89 * @ORM\OneToMany(targetEntity="Wallabag\ApiBundle\Entity\Client", mappedBy="user", cascade={"remove"})
90 */
91 protected $clients;
92
87 public function __construct() 93 public function __construct()
88 { 94 {
89 parent::__construct(); 95 parent::__construct();
@@ -240,4 +246,24 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
240 246
241 return false; 247 return false;
242 } 248 }
249
250 /**
251 * @param Client $client
252 *
253 * @return User
254 */
255 public function addClient(Client $client)
256 {
257 $this->clients[] = $client;
258
259 return $this;
260 }
261
262 /**
263 * @return ArrayCollection<Entry>
264 */
265 public function getClients()
266 {
267 return $this->clients;
268 }
243} 269}
diff --git a/src/Wallabag/UserBundle/Repository/UserRepository.php b/src/Wallabag/UserBundle/Repository/UserRepository.php
index 009c4881..f913f52d 100644
--- a/src/Wallabag/UserBundle/Repository/UserRepository.php
+++ b/src/Wallabag/UserBundle/Repository/UserRepository.php
@@ -38,4 +38,18 @@ class UserRepository extends EntityRepository
38 ->getQuery() 38 ->getQuery()
39 ->getSingleResult(); 39 ->getSingleResult();
40 } 40 }
41
42 /**
43 * Count how many users are enabled.
44 *
45 * @return int
46 */
47 public function getSumEnabledUsers()
48 {
49 return $this->createQueryBuilder('u')
50 ->select('count(u)')
51 ->andWhere('u.enabled = true')
52 ->getQuery()
53 ->getSingleScalarResult();
54 }
41} 55}
diff --git a/src/Wallabag/UserBundle/Resources/config/services.yml b/src/Wallabag/UserBundle/Resources/config/services.yml
index a8ee721b..164a25ec 100644
--- a/src/Wallabag/UserBundle/Resources/config/services.yml
+++ b/src/Wallabag/UserBundle/Resources/config/services.yml
@@ -22,7 +22,7 @@ services:
22 arguments: 22 arguments:
23 - WallabagUserBundle:User 23 - WallabagUserBundle:User
24 24
25 wallabag_user.create_config: 25 wallabag_user.listener.create_config:
26 class: Wallabag\UserBundle\EventListener\CreateConfigListener 26 class: Wallabag\UserBundle\EventListener\CreateConfigListener
27 arguments: 27 arguments:
28 - "@doctrine.orm.entity_manager" 28 - "@doctrine.orm.entity_manager"
diff --git a/src/Wallabag/UserBundle/Resources/views/Resetting/checkEmail.html.twig b/src/Wallabag/UserBundle/Resources/views/Resetting/check_email.html.twig
index 66cbdc28..e9d46dcc 100644
--- a/src/Wallabag/UserBundle/Resources/views/Resetting/checkEmail.html.twig
+++ b/src/Wallabag/UserBundle/Resources/views/Resetting/check_email.html.twig
@@ -5,7 +5,7 @@
5{% block fos_user_content %} 5{% block fos_user_content %}
6<div class="card-content"> 6<div class="card-content">
7 <div class="row"> 7 <div class="row">
8 {{ 'resetting.check_email'|trans({'%email%': email}) }} 8 <p>{{ 'resetting.check_email'|trans({'%tokenLifetime%': tokenLifetime}) }}</p>
9 </div> 9 </div>
10</div> 10</div>
11{% endblock fos_user_content %} 11{% endblock fos_user_content %}