Merge branch 'release-0.8' 0.8
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 5 Mar 2012 05:29:25 +0000 (06:29 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 5 Mar 2012 05:29:25 +0000 (06:29 +0100)
35 files changed:
pom.xml
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/core/Options.java
src/main/java/net/pterodactylus/sone/core/SoneDownloader.java
src/main/java/net/pterodactylus/sone/core/SoneInserter.java
src/main/java/net/pterodactylus/sone/core/UpdateChecker.java
src/main/java/net/pterodactylus/sone/data/Post.java
src/main/java/net/pterodactylus/sone/data/Reply.java
src/main/java/net/pterodactylus/sone/data/Sone.java
src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java
src/main/java/net/pterodactylus/sone/freenet/L10nFilter.java
src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java
src/main/java/net/pterodactylus/sone/main/SonePlugin.java
src/main/java/net/pterodactylus/sone/notify/ListNotificationFilters.java
src/main/java/net/pterodactylus/sone/template/ImageLinkFilter.java
src/main/java/net/pterodactylus/sone/template/PostAccessor.java
src/main/java/net/pterodactylus/sone/template/ProfileAccessor.java
src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java
src/main/java/net/pterodactylus/sone/template/SoneAccessor.java
src/main/java/net/pterodactylus/sone/web/KnownSonesPage.java
src/main/java/net/pterodactylus/sone/web/NewPage.java [new file with mode: 0644]
src/main/java/net/pterodactylus/sone/web/SearchPage.java
src/main/java/net/pterodactylus/sone/web/WebInterface.java
src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/JsonPage.java
src/main/resources/i18n/sone.de.properties [new file with mode: 0644]
src/main/resources/i18n/sone.en.properties
src/main/resources/i18n/sone.fr.properties [new file with mode: 0644]
src/main/resources/i18n/sone.no.properties [new file with mode: 0644]
src/main/resources/i18n/sone.ru.properties [new file with mode: 0644]
src/main/resources/static/javascript/sone.js
src/main/resources/templates/about.html
src/main/resources/templates/deleteSone.html
src/main/resources/templates/new.html [new file with mode: 0644]
src/main/resources/templates/viewSone.html

diff --git a/pom.xml b/pom.xml
index 279e6c7..a2b3eff 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
        <modelVersion>4.0.0</modelVersion>
        <groupId>net.pterodactylus</groupId>
        <artifactId>sone</artifactId>
-       <version>0.7.6</version>
+       <version>0.8</version>
        <dependencies>
                <dependency>
                        <groupId>net.pterodactylus</groupId>
index a51a189..296d080 100644 (file)
@@ -24,8 +24,8 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.logging.Level;
@@ -40,11 +40,12 @@ import net.pterodactylus.sone.data.Image;
 import net.pterodactylus.sone.data.Post;
 import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Profile;
+import net.pterodactylus.sone.data.Profile.Field;
 import net.pterodactylus.sone.data.Reply;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.data.Sone.ShowCustomAvatars;
+import net.pterodactylus.sone.data.Sone.SoneStatus;
 import net.pterodactylus.sone.data.TemporaryImage;
-import net.pterodactylus.sone.data.Profile.Field;
 import net.pterodactylus.sone.fcp.FcpInterface;
 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
 import net.pterodactylus.sone.freenet.wot.Identity;
@@ -74,26 +75,6 @@ import freenet.keys.FreenetURI;
  */
 public class Core extends AbstractService implements IdentityListener, UpdateListener, SoneProvider, PostProvider, SoneInsertListener, ImageInsertListener {
 
-       /**
-        * Enumeration for the possible states of a {@link Sone}.
-        *
-        * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
-        */
-       public enum SoneStatus {
-
-               /** The Sone is unknown, i.e. not yet downloaded. */
-               unknown,
-
-               /** The Sone is idle, i.e. not being downloaded or inserted. */
-               idle,
-
-               /** The Sone is currently being inserted. */
-               inserting,
-
-               /** The Sone is currently being downloaded. */
-               downloading,
-       }
-
        /** The logger. */
        private static final Logger logger = Logging.getLogger(Core.class);
 
@@ -133,10 +114,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        /** The FCP interface. */
        private volatile FcpInterface fcpInterface;
 
-       /** The Sones’ statuses. */
-       /* synchronize access on itself. */
-       private final Map<Sone, SoneStatus> soneStatuses = new HashMap<Sone, SoneStatus>();
-
        /** The times Sones were followed. */
        private final Map<Sone, Long> soneFollowingTimes = new HashMap<Sone, Long>();
 
@@ -160,29 +137,18 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        /* synchronize access on this on itself. */
        private Map<String, Sone> remoteSones = new HashMap<String, Sone>();
 
-       /** All new Sones. */
-       private Set<String> newSones = new HashSet<String>();
-
        /** All known Sones. */
-       /* synchronize access on {@link #newSones}. */
        private Set<String> knownSones = new HashSet<String>();
 
        /** All posts. */
        private Map<String, Post> posts = new HashMap<String, Post>();
 
-       /** All new posts. */
-       private Set<String> newPosts = new HashSet<String>();
-
        /** All known posts. */
-       /* synchronize access on {@link #newPosts}. */
        private Set<String> knownPosts = new HashSet<String>();
 
        /** All replies. */
        private Map<String, PostReply> replies = new HashMap<String, PostReply>();
 
-       /** All new replies. */
-       private Set<String> newReplies = new HashSet<String>();
-
        /** All known replies. */
        private Set<String> knownReplies = new HashSet<String>();
 
@@ -306,33 +272,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        }
 
        /**
-        * Returns the status of the given Sone.
-        *
-        * @param sone
-        *            The Sone to get the status for
-        * @return The status of the Sone
-        */
-       public SoneStatus getSoneStatus(Sone sone) {
-               synchronized (soneStatuses) {
-                       return soneStatuses.get(sone);
-               }
-       }
-
-       /**
-        * Sets the status of the given Sone.
-        *
-        * @param sone
-        *            The Sone to set the status of
-        * @param soneStatus
-        *            The status to set
-        */
-       public void setSoneStatus(Sone sone, SoneStatus soneStatus) {
-               synchronized (soneStatuses) {
-                       soneStatuses.put(sone, soneStatus);
-               }
-       }
-
-       /**
         * Returns the Sone rescuer for the given local Sone.
         *
         * @param sone
@@ -488,7 +427,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        if ((sone == null) && create) {
                                sone = new Sone(id);
                                localSones.put(id, sone);
-                               setSoneStatus(sone, SoneStatus.unknown);
                        }
                        return sone;
                }
@@ -521,7 +459,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        if ((sone == null) && create && (id != null) && (id.length() == 43)) {
                                sone = new Sone(id);
                                remoteSones.put(id, sone);
-                               setSoneStatus(sone, SoneStatus.unknown);
                        }
                        return sone;
                }
@@ -556,19 +493,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        }
 
        /**
-        * Returns whether the Sone with the given ID is a new Sone.
-        *
-        * @param soneId
-        *            The ID of the sone to check for
-        * @return {@code true} if the given Sone is new, false otherwise
-        */
-       public boolean isNewSone(String soneId) {
-               synchronized (newSones) {
-                       return !knownSones.contains(soneId) && newSones.contains(soneId);
-               }
-       }
-
-       /**
         * Returns whether the given Sone has been modified.
         *
         * @param sone
@@ -645,20 +569,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        }
 
        /**
-        * Returns whether the given post ID is new.
-        *
-        * @param postId
-        *            The post ID
-        * @return {@code true} if the post is considered to be new, {@code false}
-        *         otherwise
-        */
-       public boolean isNewPost(String postId) {
-               synchronized (newPosts) {
-                       return !knownPosts.contains(postId) && newPosts.contains(postId);
-               }
-       }
-
-       /**
         * Returns all posts that have the given Sone as recipient.
         *
         * @see Post#getRecipient()
@@ -736,20 +646,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        }
 
        /**
-        * Returns whether the reply with the given ID is new.
-        *
-        * @param replyId
-        *            The ID of the reply to check
-        * @return {@code true} if the reply is considered to be new, {@code false}
-        *         otherwise
-        */
-       public boolean isNewReply(String replyId) {
-               synchronized (newReplies) {
-                       return !knownReplies.contains(replyId) && newReplies.contains(replyId);
-               }
-       }
-
-       /**
         * Returns all Sones that have liked the given post.
         *
         * @param post
@@ -967,12 +863,13 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        }
                        sone.setLatestEdition(Numbers.safeParseLong(ownIdentity.getProperty("Sone.LatestEdition"), (long) 0));
                        sone.setClient(new Client("Sone", SonePlugin.VERSION.toString()));
+                       sone.setKnown(true);
                        /* TODO - load posts ’n stuff */
                        localSones.put(ownIdentity.getId(), sone);
                        final SoneInserter soneInserter = new SoneInserter(this, freenetInterface, sone);
                        soneInserter.addSoneInsertListener(this);
                        soneInserters.put(sone, soneInserter);
-                       setSoneStatus(sone, SoneStatus.idle);
+                       sone.setStatus(SoneStatus.idle);
                        loadSone(sone);
                        soneInserter.start();
                        return sone;
@@ -1024,12 +921,10 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        sone.setRequestUri(getSoneUri(identity.getRequestUri()));
                        sone.setLatestEdition(Numbers.safeParseLong(identity.getProperty("Sone.LatestEdition"), (long) 0));
                        if (newSone) {
-                               synchronized (newSones) {
+                               synchronized (knownSones) {
                                        newSone = !knownSones.contains(sone.getId());
-                                       if (newSone) {
-                                               newSones.add(sone.getId());
-                                       }
                                }
+                               sone.setKnown(!newSone);
                                if (newSone) {
                                        coreListenerManager.fireNewSoneFound(sone);
                                        for (Sone localSone : getLocalSones()) {
@@ -1040,7 +935,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                                }
                        }
                        soneDownloader.addSone(sone);
-                       setSoneStatus(sone, SoneStatus.unknown);
                        soneDownloaders.execute(new Runnable() {
 
                                @Override
@@ -1272,14 +1166,14 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                                        }
                                }
                                List<Post> storedPosts = storedSone.getPosts();
-                               synchronized (newPosts) {
+                               synchronized (knownPosts) {
                                        for (Post post : sone.getPosts()) {
-                                               post.setSone(storedSone);
+                                               post.setSone(storedSone).setKnown(knownPosts.contains(post.getId()));
                                                if (!storedPosts.contains(post)) {
                                                        if (post.getTime() < getSoneFollowingTime(sone)) {
                                                                knownPosts.add(post.getId());
                                                        } else if (!knownPosts.contains(post.getId())) {
-                                                               newPosts.add(post.getId());
+                                                               sone.setKnown(false);
                                                                coreListenerManager.fireNewPostFound(post);
                                                        }
                                                }
@@ -1297,14 +1191,14 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                                        }
                                }
                                Set<PostReply> storedReplies = storedSone.getReplies();
-                               synchronized (newReplies) {
+                               synchronized (knownReplies) {
                                        for (PostReply reply : sone.getReplies()) {
-                                               reply.setSone(storedSone);
+                                               reply.setSone(storedSone).setKnown(knownReplies.contains(reply.getId()));
                                                if (!storedReplies.contains(reply)) {
                                                        if (reply.getTime() < getSoneFollowingTime(sone)) {
                                                                knownReplies.add(reply.getId());
                                                        } else if (!knownReplies.contains(reply.getId())) {
-                                                               newReplies.add(reply.getId());
+                                                               reply.setKnown(false);
                                                                coreListenerManager.fireNewReplyFound(reply);
                                                        }
                                                }
@@ -1399,19 +1293,20 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        }
 
        /**
-        * Marks the given Sone as known. If the Sone was {@link #isNewPost(String)
-        * new} before, a {@link CoreListener#markSoneKnown(Sone)} event is fired.
+        * Marks the given Sone as known. If the Sone was not {@link Post#isKnown()
+        * known} before, a {@link CoreListener#markSoneKnown(Sone)} event is fired.
         *
         * @param sone
         *            The Sone to mark as known
         */
        public void markSoneKnown(Sone sone) {
-               synchronized (newSones) {
-                       if (newSones.remove(sone.getId())) {
+               if (!sone.isKnown()) {
+                       sone.setKnown(true);
+                       synchronized (knownSones) {
                                knownSones.add(sone.getId());
-                               coreListenerManager.fireMarkSoneKnown(sone);
-                               touchConfiguration();
                        }
+                       coreListenerManager.fireMarkSoneKnown(sone);
+                       touchConfiguration();
                }
        }
 
@@ -1622,17 +1517,17 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        sone.setAlbums(topLevelAlbums);
                        soneInserters.get(sone).setLastInsertFingerprint(lastInsertFingerprint);
                }
-               synchronized (newSones) {
+               synchronized (knownSones) {
                        for (String friend : friends) {
                                knownSones.add(friend);
                        }
                }
-               synchronized (newPosts) {
+               synchronized (knownPosts) {
                        for (Post post : posts) {
                                knownPosts.add(post.getId());
                        }
                }
-               synchronized (newReplies) {
+               synchronized (knownReplies) {
                        for (PostReply reply : replies) {
                                knownReplies.add(reply.getId());
                        }
@@ -1709,10 +1604,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                synchronized (posts) {
                        posts.put(post.getId(), post);
                }
-               synchronized (newPosts) {
-                       newPosts.add(post.getId());
-                       coreListenerManager.fireNewPostFound(post);
-               }
+               coreListenerManager.fireNewPostFound(post);
                sone.addPost(post);
                touchConfiguration();
                localElementTicker.registerEvent(System.currentTimeMillis() + 10 * 1000, new Runnable() {
@@ -1744,28 +1636,28 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        posts.remove(post.getId());
                }
                coreListenerManager.firePostRemoved(post);
-               synchronized (newPosts) {
-                       markPostKnown(post);
-                       knownPosts.remove(post.getId());
-               }
+               markPostKnown(post);
                touchConfiguration();
        }
 
        /**
-        * Marks the given post as known, if it is currently a new post (according
-        * to {@link #isNewPost(String)}).
+        * Marks the given post as known, if it is currently not a known post
+        * (according to {@link Post#isKnown()}).
         *
         * @param post
         *            The post to mark as known
         */
        public void markPostKnown(Post post) {
-               synchronized (newPosts) {
-                       if (newPosts.remove(post.getId())) {
-                               knownPosts.add(post.getId());
-                               coreListenerManager.fireMarkPostKnown(post);
+               post.setKnown(true);
+               synchronized (knownPosts) {
+                       coreListenerManager.fireMarkPostKnown(post);
+                       if (knownPosts.add(post.getId())) {
                                touchConfiguration();
                        }
                }
+               for (PostReply reply : getReplies(post)) {
+                       markReplyKnown(reply);
+               }
        }
 
        /**
@@ -1849,8 +1741,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                synchronized (replies) {
                        replies.put(reply.getId(), reply);
                }
-               synchronized (newReplies) {
-                       newReplies.add(reply.getId());
+               synchronized (knownReplies) {
                        coreListenerManager.fireNewReplyFound(reply);
                }
                sone.addReply(reply);
@@ -1883,7 +1774,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                synchronized (replies) {
                        replies.remove(reply.getId());
                }
-               synchronized (newReplies) {
+               synchronized (knownReplies) {
                        markReplyKnown(reply);
                        knownReplies.remove(reply.getId());
                }
@@ -1892,17 +1783,17 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
        }
 
        /**
-        * Marks the given reply as known, if it is currently a new reply (according
-        * to {@link #isNewReply(String)}).
+        * Marks the given reply as known, if it is currently not a known reply
+        * (according to {@link Reply#isKnown()}).
         *
         * @param reply
         *            The reply to mark as known
         */
        public void markReplyKnown(PostReply reply) {
-               synchronized (newReplies) {
-                       if (newReplies.remove(reply.getId())) {
-                               knownReplies.add(reply.getId());
-                               coreListenerManager.fireMarkReplyKnown(reply);
+               reply.setKnown(true);
+               synchronized (knownReplies) {
+                       coreListenerManager.fireMarkReplyKnown(reply);
+                       if (knownReplies.add(reply.getId())) {
                                touchConfiguration();
                        }
                }
@@ -2285,7 +2176,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
 
                        /* save known Sones. */
                        int soneCounter = 0;
-                       synchronized (newSones) {
+                       synchronized (knownSones) {
                                for (String knownSoneId : knownSones) {
                                        configuration.getStringValue("KnownSone/" + soneCounter++ + "/ID").setValue(knownSoneId);
                                }
@@ -2305,7 +2196,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
 
                        /* save known posts. */
                        int postCounter = 0;
-                       synchronized (newPosts) {
+                       synchronized (knownPosts) {
                                for (String knownPostId : knownPosts) {
                                        configuration.getStringValue("KnownPosts/" + postCounter++ + "/ID").setValue(knownPostId);
                                }
@@ -2314,7 +2205,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
 
                        /* save known replies. */
                        int replyCounter = 0;
-                       synchronized (newReplies) {
+                       synchronized (knownReplies) {
                                for (String knownReplyId : knownReplies) {
                                        configuration.getStringValue("KnownReplies/" + replyCounter++ + "/ID").setValue(knownReplyId);
                                }
@@ -2414,7 +2305,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        if (knownSoneId == null) {
                                break;
                        }
-                       synchronized (newSones) {
+                       synchronized (knownSones) {
                                knownSones.add(knownSoneId);
                        }
                }
@@ -2445,7 +2336,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        if (knownPostId == null) {
                                break;
                        }
-                       synchronized (newPosts) {
+                       synchronized (knownPosts) {
                                knownPosts.add(knownPostId);
                        }
                }
@@ -2457,7 +2348,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        if (knownReplyId == null) {
                                break;
                        }
-                       synchronized (newReplies) {
+                       synchronized (knownReplies) {
                                knownReplies.add(knownReplyId);
                        }
                }
@@ -2587,19 +2478,17 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                        return;
                }
                synchronized (posts) {
-                       synchronized (newPosts) {
+                       synchronized (knownPosts) {
                                for (Post post : sone.getPosts()) {
                                        posts.remove(post.getId());
-                                       newPosts.remove(post.getId());
                                        coreListenerManager.firePostRemoved(post);
                                }
                        }
                }
                synchronized (replies) {
-                       synchronized (newReplies) {
+                       synchronized (knownReplies) {
                                for (PostReply reply : sone.getReplies()) {
                                        replies.remove(reply.getId());
-                                       newReplies.remove(reply.getId());
                                        coreListenerManager.fireReplyRemoved(reply);
                                }
                        }
@@ -2607,10 +2496,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                synchronized (remoteSones) {
                        remoteSones.remove(identity.getId());
                }
-               synchronized (newSones) {
-                       newSones.remove(identity.getId());
-                       coreListenerManager.fireSoneRemoved(sone);
-               }
+               coreListenerManager.fireSoneRemoved(sone);
        }
 
        //
@@ -2731,8 +2617,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis
                 *
                 * @param insertionDelay
                 *            The insertion delay to validate
-                * @return {@code true} if the given insertion delay was valid, {@code
-                *         false} otherwise
+                * @return {@code true} if the given insertion delay was valid,
+                *         {@code false} otherwise
                 */
                public boolean validateInsertionDelay(Integer insertionDelay) {
                        return options.getIntegerOption("InsertionDelay").validate(insertionDelay);
index f280aae..bf51e02 100644 (file)
 
 package net.pterodactylus.sone.core;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import net.pterodactylus.util.validation.Validator;
@@ -133,7 +130,29 @@ public class Options {
                private Validator<T> validator;
 
                /** The option watcher. */
-               private final List<OptionWatcher<T>> optionWatchers = new ArrayList<OptionWatcher<T>>();
+               private final OptionWatcher<T> optionWatcher;
+
+               /**
+                * Creates a new default option.
+                *
+                * @param defaultValue
+                *            The default value of the option
+                */
+               public DefaultOption(T defaultValue) {
+                       this(defaultValue, (OptionWatcher<T>) null);
+               }
+
+               /**
+                * Creates a new default option.
+                *
+                * @param defaultValue
+                *            The default value of the option
+                * @param validator
+                *            The validator for value validation (may be {@code null})
+                */
+               public DefaultOption(T defaultValue, Validator<T> validator) {
+                       this(defaultValue, validator, null);
+               }
 
                /**
                 * Creates a new default option.
@@ -141,9 +160,9 @@ public class Options {
                 * @param defaultValue
                 *            The default value of the option
                 * @param optionWatchers
-                *            The option watchers
+                *            The option watchers (may be {@code null})
                 */
-               public DefaultOption(T defaultValue, OptionWatcher<T>... optionWatchers) {
+               public DefaultOption(T defaultValue, OptionWatcher<T> optionWatchers) {
                        this(defaultValue, null, optionWatchers);
                }
 
@@ -153,14 +172,14 @@ public class Options {
                 * @param defaultValue
                 *            The default value of the option
                 * @param validator
-                *            The validator for value validation
-                * @param optionWatchers
-                *            The option watchers
+                *            The validator for value validation (may be {@code null})
+                * @param optionWatcher
+                *            The option watcher (may be {@code null})
                 */
-               public DefaultOption(T defaultValue, Validator<T> validator, OptionWatcher<T>... optionWatchers) {
+               public DefaultOption(T defaultValue, Validator<T> validator, OptionWatcher<T> optionWatcher) {
                        this.defaultValue = defaultValue;
                        this.validator = validator;
-                       this.optionWatchers.addAll(Arrays.asList(optionWatchers));
+                       this.optionWatcher = optionWatcher;
                }
 
                /**
@@ -209,7 +228,7 @@ public class Options {
                        T oldValue = this.value;
                        this.value = value;
                        if (!get().equals(oldValue)) {
-                               for (OptionWatcher<T> optionWatcher : optionWatchers) {
+                               if (optionWatcher != null) {
                                        optionWatcher.optionChanged(this, oldValue, get());
                                }
                        }
@@ -336,6 +355,7 @@ public class Options {
         * @return The enum option, or {@code null} if there is no enum option with
         *         the given name
         */
+       @SuppressWarnings("unchecked")
        public <T extends Enum<T>> Option<T> getEnumOption(String name) {
                return (Option<T>) enumOptions.get(name);
        }
index 5024ab9..90f926a 100644 (file)
@@ -26,7 +26,6 @@ import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import net.pterodactylus.sone.core.Core.SoneStatus;
 import net.pterodactylus.sone.data.Album;
 import net.pterodactylus.sone.data.Client;
 import net.pterodactylus.sone.data.Image;
@@ -34,6 +33,7 @@ import net.pterodactylus.sone.data.Post;
 import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Profile;
 import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.data.Sone.SoneStatus;
 import net.pterodactylus.util.collection.Pair;
 import net.pterodactylus.util.io.Closer;
 import net.pterodactylus.util.logging.Logging;
@@ -153,7 +153,7 @@ public class SoneDownloader extends AbstractService {
        public Sone fetchSone(Sone sone, FreenetURI soneUri, boolean fetchOnly) {
                logger.log(Level.FINE, "Starting fetch for Sone “%s” from %s…", new Object[] { sone, soneUri });
                FreenetURI requestUri = soneUri.setMetaString(new String[] { "sone.xml" });
-               core.setSoneStatus(sone, SoneStatus.downloading);
+               sone.setStatus(SoneStatus.downloading);
                try {
                        Pair<FreenetURI, FetchResult> fetchResults = freenetInterface.fetchUri(requestUri);
                        if (fetchResults == null) {
@@ -170,7 +170,7 @@ public class SoneDownloader extends AbstractService {
                        }
                        return parsedSone;
                } finally {
-                       core.setSoneStatus(sone, (sone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle);
+                       sone.setStatus((sone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle);
                }
        }
 
index 4d9878f..ccf8a21 100644 (file)
@@ -27,11 +27,11 @@ import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import net.pterodactylus.sone.core.Core.SoneStatus;
 import net.pterodactylus.sone.data.Post;
 import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Reply;
 import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.data.Sone.SoneStatus;
 import net.pterodactylus.sone.freenet.StringBucket;
 import net.pterodactylus.sone.main.SonePlugin;
 import net.pterodactylus.util.collection.ListBuilder;
@@ -233,7 +233,7 @@ public class SoneInserter extends AbstractService {
 
                                boolean success = false;
                                try {
-                                       core.setSoneStatus(sone, SoneStatus.inserting);
+                                       sone.setStatus(SoneStatus.inserting);
                                        long insertTime = System.currentTimeMillis();
                                        insertInformation.setTime(insertTime);
                                        soneInsertListenerManager.fireInsertStarted();
@@ -253,7 +253,7 @@ public class SoneInserter extends AbstractService {
                                        soneInsertListenerManager.fireInsertAborted(se1);
                                        logger.log(Level.WARNING, "Could not insert Sone “" + sone.getName() + "”!", se1);
                                } finally {
-                                       core.setSoneStatus(sone, SoneStatus.idle);
+                                       sone.setStatus(SoneStatus.idle);
                                }
 
                                /*
index 9c50f37..a6f7a21 100644 (file)
@@ -49,7 +49,7 @@ public class UpdateChecker {
        private static final String SONE_HOMEPAGE = "USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/";
 
        /** The current latest known edition. */
-       private static final int LATEST_EDITION = 36;
+       private static final int LATEST_EDITION = 49;
 
        /** The Freenet interface. */
        private final FreenetInterface freenetInterface;
index a28bf9f..1a29480 100644 (file)
@@ -65,6 +65,9 @@ public class Post {
        /** The text of the post. */
        private volatile String text;
 
+       /** Whether the post is known. */
+       private volatile boolean known;
+
        /**
         * Creates a new post.
         *
@@ -219,6 +222,27 @@ public class Post {
                return this;
        }
 
+       /**
+        * Returns whether this post is known.
+        *
+        * @return {@code true} if this post is known, {@code false} otherwise
+        */
+       public boolean isKnown() {
+               return known;
+       }
+
+       /**
+        * Sets whether this post is known.
+        *
+        * @param known
+        *            {@code true} if this post is known, {@code false} otherwise
+        * @return This post
+        */
+       public Post setKnown(boolean known) {
+               this.known = known;
+               return this;
+       }
+
        //
        // OBJECT METHODS
        //
index 780fe69..15d8287 100644 (file)
@@ -69,6 +69,9 @@ public abstract class Reply<T extends Reply<T>> {
        /** The text of the reply. */
        private volatile String text;
 
+       /** Whether the reply is known. */
+       private volatile boolean known;
+
        /**
         * Creates a new reply with the given ID.
         *
@@ -187,6 +190,28 @@ public abstract class Reply<T extends Reply<T>> {
                return (T) this;
        }
 
+       /**
+        * Returns whether this reply is known.
+        *
+        * @return {@code true} if this reply is known, {@code false} otherwise
+        */
+       public boolean isKnown() {
+               return known;
+       }
+
+       /**
+        * Sets whether this reply is known.
+        *
+        * @param known
+        *            {@code true} if this reply is known, {@code false} otherwise
+        * @return This reply
+        */
+       @SuppressWarnings("unchecked")
+       public T setKnown(boolean known) {
+               this.known = known;
+               return (T) this;
+       }
+
        //
        // OBJECT METHODS
        //
index 901d676..c2f9ae1 100644 (file)
@@ -21,9 +21,10 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -48,6 +49,26 @@ import freenet.keys.FreenetURI;
 public class Sone implements Fingerprintable, Comparable<Sone> {
 
        /**
+        * Enumeration for the possible states of a {@link Sone}.
+        *
+        * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+        */
+       public enum SoneStatus {
+
+               /** The Sone is unknown, i.e. not yet downloaded. */
+               unknown,
+
+               /** The Sone is idle, i.e. not being downloaded or inserted. */
+               idle,
+
+               /** The Sone is currently being inserted. */
+               inserting,
+
+               /** The Sone is currently being downloaded. */
+               downloading,
+       }
+
+       /**
         * The possible values for the “show custom avatars” option.
         *
         * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
@@ -170,29 +191,35 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
        /** The time of the last inserted update. */
        private volatile long time;
 
+       /** The status of this Sone. */
+       private volatile SoneStatus status = SoneStatus.unknown;
+
        /** The profile of this Sone. */
        private volatile Profile profile = new Profile(this);
 
        /** The client used by the Sone. */
        private volatile Client client;
 
+       /** Whether this Sone is known. */
+       private volatile boolean known;
+
        /** All friend Sones. */
-       private final Set<String> friendSones = Collections.synchronizedSet(new HashSet<String>());
+       private final Set<String> friendSones = new CopyOnWriteArraySet<String>();
 
        /** All posts. */
-       private final Set<Post> posts = Collections.synchronizedSet(new HashSet<Post>());
+       private final Set<Post> posts = new CopyOnWriteArraySet<Post>();
 
        /** All replies. */
-       private final Set<PostReply> replies = Collections.synchronizedSet(new HashSet<PostReply>());
+       private final Set<PostReply> replies = new CopyOnWriteArraySet<PostReply>();
 
        /** The IDs of all liked posts. */
-       private final Set<String> likedPostIds = Collections.synchronizedSet(new HashSet<String>());
+       private final Set<String> likedPostIds = new CopyOnWriteArraySet<String>();
 
        /** The IDs of all liked replies. */
-       private final Set<String> likedReplyIds = Collections.synchronizedSet(new HashSet<String>());
+       private final Set<String> likedReplyIds = new CopyOnWriteArraySet<String>();
 
        /** The albums of this Sone. */
-       private final List<Album> albums = Collections.synchronizedList(new ArrayList<Album>());
+       private final List<Album> albums = new CopyOnWriteArrayList<Album>();
 
        /** Sone-specific options. */
        private final Options options = new Options();
@@ -359,13 +386,37 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
        }
 
        /**
+        * Returns the status of this Sone.
+        *
+        * @return The status of this Sone
+        */
+       public SoneStatus getStatus() {
+               return status;
+       }
+
+       /**
+        * Sets the new status of this Sone.
+        *
+        * @param status
+        *            The new status of this Sone
+        * @return This Sone
+        * @throws IllegalArgumentException
+        *             if {@code status} is {@code null}
+        */
+       public Sone setStatus(SoneStatus status) {
+               Validation.begin().isNotNull("Sone Status", status).check();
+               this.status = status;
+               return this;
+       }
+
+       /**
         * Returns a copy of the profile. If you want to update values in the
         * profile of this Sone, update the values in the returned {@link Profile}
         * and use {@link #setProfile(Profile)} to change the profile in this Sone.
         *
         * @return A copy of the profile
         */
-       public synchronized Profile getProfile() {
+       public Profile getProfile() {
                return new Profile(profile);
        }
 
@@ -377,7 +428,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param profile
         *            The profile to set
         */
-       public synchronized void setProfile(Profile profile) {
+       public void setProfile(Profile profile) {
                this.profile = new Profile(profile);
        }
 
@@ -403,6 +454,27 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
        }
 
        /**
+        * Returns whether this Sone is known.
+        *
+        * @return {@code true} if this Sone is known, {@code false} otherwise
+        */
+       public boolean isKnown() {
+               return known;
+       }
+
+       /**
+        * Sets whether this Sone is known.
+        *
+        * @param known
+        *            {@code true} if this Sone is known, {@code false} otherwise
+        * @return This Sone
+        */
+       public Sone setKnown(boolean known) {
+               this.known = known;
+               return this;
+       }
+
+       /**
         * Returns all friend Sones of this Sone.
         *
         * @return The friend Sones of this Sone
@@ -471,7 +543,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The new (and only) posts of this Sone
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone setPosts(Collection<Post> posts) {
+       public Sone setPosts(Collection<Post> posts) {
                synchronized (this) {
                        this.posts.clear();
                        this.posts.addAll(posts);
@@ -486,7 +558,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param post
         *            The post to add
         */
-       public synchronized void addPost(Post post) {
+       public void addPost(Post post) {
                if (post.getSone().equals(this) && posts.add(post)) {
                        logger.log(Level.FINEST, "Adding %s to “%s”.", new Object[] { post, getName() });
                }
@@ -498,7 +570,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param post
         *            The post to remove
         */
-       public synchronized void removePost(Post post) {
+       public void removePost(Post post) {
                if (post.getSone().equals(this)) {
                        posts.remove(post);
                }
@@ -509,7 +581,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *
         * @return All replies this Sone made
         */
-       public synchronized Set<PostReply> getReplies() {
+       public Set<PostReply> getReplies() {
                return Collections.unmodifiableSet(replies);
        }
 
@@ -520,7 +592,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The new (and only) replies of this Sone
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone setReplies(Collection<PostReply> replies) {
+       public Sone setReplies(Collection<PostReply> replies) {
                this.replies.clear();
                this.replies.addAll(replies);
                return this;
@@ -533,7 +605,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param reply
         *            The reply to add
         */
-       public synchronized void addReply(PostReply reply) {
+       public void addReply(PostReply reply) {
                if (reply.getSone().equals(this)) {
                        replies.add(reply);
                }
@@ -545,7 +617,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param reply
         *            The reply to remove
         */
-       public synchronized void removeReply(PostReply reply) {
+       public void removeReply(PostReply reply) {
                if (reply.getSone().equals(this)) {
                        replies.remove(reply);
                }
@@ -567,7 +639,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            All liked posts’ IDs
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone setLikePostIds(Set<String> likedPostIds) {
+       public Sone setLikePostIds(Set<String> likedPostIds) {
                this.likedPostIds.clear();
                this.likedPostIds.addAll(likedPostIds);
                return this;
@@ -592,7 +664,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The ID of the post
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone addLikedPostId(String postId) {
+       public Sone addLikedPostId(String postId) {
                likedPostIds.add(postId);
                return this;
        }
@@ -604,7 +676,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The ID of the post
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone removeLikedPostId(String postId) {
+       public Sone removeLikedPostId(String postId) {
                likedPostIds.remove(postId);
                return this;
        }
@@ -625,7 +697,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            All liked replies’ IDs
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone setLikeReplyIds(Set<String> likedReplyIds) {
+       public Sone setLikeReplyIds(Set<String> likedReplyIds) {
                this.likedReplyIds.clear();
                this.likedReplyIds.addAll(likedReplyIds);
                return this;
@@ -650,7 +722,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The ID of the reply
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone addLikedReplyId(String replyId) {
+       public Sone addLikedReplyId(String replyId) {
                likedReplyIds.add(replyId);
                return this;
        }
@@ -662,7 +734,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The ID of the reply
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone removeLikedReplyId(String replyId) {
+       public Sone removeLikedReplyId(String replyId) {
                likedReplyIds.remove(replyId);
                return this;
        }
@@ -717,7 +789,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param album
         *            The album to add
         */
-       public synchronized void addAlbum(Album album) {
+       public void addAlbum(Album album) {
                Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
                albums.add(album);
        }
@@ -728,7 +800,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param albums
         *            The albums of this Sone
         */
-       public synchronized void setAlbums(Collection<? extends Album> albums) {
+       public void setAlbums(Collection<? extends Album> albums) {
                Validation.begin().isNotNull("Albums", albums).check();
                this.albums.clear();
                for (Album album : albums) {
@@ -742,7 +814,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param album
         *            The album to remove
         */
-       public synchronized void removeAlbum(Album album) {
+       public void removeAlbum(Album album) {
                Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
                albums.remove(album);
        }
index ab705d7..3a246c3 100644 (file)
@@ -24,9 +24,9 @@ import net.pterodactylus.sone.core.Core;
 import net.pterodactylus.sone.data.Post;
 import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Profile;
+import net.pterodactylus.sone.data.Profile.Field;
 import net.pterodactylus.sone.data.Reply;
 import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.data.Profile.Field;
 import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder;
 import net.pterodactylus.sone.freenet.fcp.AbstractCommand;
 import net.pterodactylus.sone.freenet.fcp.Command;
index 910e0d6..16dc9fb 100644 (file)
@@ -23,9 +23,9 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
+import net.pterodactylus.sone.web.WebInterface;
 import net.pterodactylus.util.template.Filter;
 import net.pterodactylus.util.template.TemplateContext;
-import freenet.l10n.BaseL10n;
 
 /**
  * {@link Filter} implementation replaces {@link String} values with their
@@ -35,17 +35,17 @@ import freenet.l10n.BaseL10n;
  */
 public class L10nFilter implements Filter {
 
-       /** The l10n handler. */
-       private final BaseL10n l10n;
+       /** The web interface. */
+       private final WebInterface webInterface;
 
        /**
         * Creates a new L10n filter.
         *
-        * @param l10n
-        *            The l10n handler
+        * @param webInterface
+        *            The Sone web interface
         */
-       public L10nFilter(BaseL10n l10n) {
-               this.l10n = l10n;
+       public L10nFilter(WebInterface webInterface) {
+               this.webInterface = webInterface;
        }
 
        /**
@@ -54,7 +54,7 @@ public class L10nFilter implements Filter {
        @Override
        public String format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
                if (parameters.isEmpty()) {
-                       return l10n.getString(String.valueOf(data));
+                       return webInterface.getL10n().getString(String.valueOf(data));
                }
                List<Object> parameterValues = new ArrayList<Object>();
                int parameterIndex = 0;
@@ -68,6 +68,6 @@ public class L10nFilter implements Filter {
                        parameterValues.add(value);
                        ++parameterIndex;
                }
-               return new MessageFormat(l10n.getString(String.valueOf(data)), new Locale(l10n.getSelectedLanguage().shortCode)).format(parameterValues.toArray());
+               return new MessageFormat(webInterface.getL10n().getString(String.valueOf(data)), new Locale(webInterface.getL10n().getSelectedLanguage().shortCode)).format(parameterValues.toArray());
        }
 }
index 69af0ca..8b95e1a 100644 (file)
@@ -45,6 +45,7 @@ import net.pterodactylus.util.service.AbstractService;
 public class IdentityManager extends AbstractService {
 
        /** Object used for synchronization. */
+       @SuppressWarnings("hiding")
        private final Object syncObject = new Object() {
                /* inner class for better lock names. */
        };
index af52a7f..ffd5d92 100644 (file)
@@ -83,7 +83,7 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr
        }
 
        /** The version. */
-       public static final Version VERSION = new Version(0, 7, 6);
+       public static final Version VERSION = new Version(0, 8);
 
        /** The logger. */
        private static final Logger logger = Logging.getLogger(SonePlugin.class);
index 7b9eb49..c7b888f 100644 (file)
@@ -164,6 +164,29 @@ public class ListNotificationFilters {
        }
 
        /**
+        * Filters the given posts, using {@link #isPostVisible(Sone, Post)} to
+        * decide whether a post should be contained in the returned list. If
+        * {@code currentSone} is not {@code null} it is used to filter out posts
+        * that are from Sones that are not followed or not trusted by the given
+        * Sone.
+        *
+        * @param posts
+        *            The posts to filter
+        * @param currentSone
+        *            The current Sone (may be {@code null})
+        * @return The filtered posts
+        */
+       public static List<Post> filterPosts(Collection<Post> posts, Sone currentSone) {
+               List<Post> filteredPosts = new ArrayList<Post>();
+               for (Post post : posts) {
+                       if (isPostVisible(currentSone, post)) {
+                               filteredPosts.add(post);
+                       }
+               }
+               return filteredPosts;
+       }
+
+       /**
         * Checks whether a post is visible to the given Sone. A post is not
         * considered visible if one of the following statements is true:
         * <ul>
index 1684be7..a79cb0b 100644 (file)
@@ -71,7 +71,8 @@ public class ImageLinkFilter implements Filter {
                        image = core.getImage((String) data, false);
                } else if (data instanceof Image) {
                        image = (Image) data;
-               } else {
+               }
+               if (image == null) {
                        return null;
                }
                String imageClass = parameters.get("class");
index bef94d6..93ff569 100644 (file)
@@ -63,7 +63,7 @@ public class PostAccessor extends ReflectionAccessor {
                        Sone currentSone = (Sone) templateContext.get("currentSone");
                        return (currentSone != null) && (currentSone.isLikedPostId(post.getId()));
                } else if (member.equals("new")) {
-                       return core.isNewPost(post.getId());
+                       return !post.isKnown();
                } else if (member.equals("bookmarked")) {
                        return core.isBookmarked(post);
                } else if (member.equals("loaded")) {
index 97be0cd..366e071 100644 (file)
@@ -60,21 +60,28 @@ public class ProfileAccessor extends ReflectionAccessor {
                                /* not logged in? don’t show custom avatars, then. */
                                return null;
                        }
+                       String avatarId = profile.getAvatar();
+                       if (avatarId == null) {
+                               return null;
+                       }
+                       if (core.getImage(avatarId, false) == null) {
+                               /* avatar ID but no matching image? show nothing. */
+                               return null;
+                       }
                        Sone remoteSone = profile.getSone();
                        if (core.isLocalSone(remoteSone)) {
                                /* always show your own avatars. */
-                               return profile.getAvatar();
+                               return avatarId;
                        }
                        ShowCustomAvatars showCustomAvatars = currentSone.getOptions().<ShowCustomAvatars> getEnumOption("ShowCustomAvatars").get();
                        if (showCustomAvatars == ShowCustomAvatars.NEVER) {
                                return null;
                        }
-                       String avatarId = profile.getAvatar();
-                       if ((showCustomAvatars == ShowCustomAvatars.ALWAYS) || (avatarId == null)) {
+                       if (showCustomAvatars == ShowCustomAvatars.ALWAYS) {
                                return avatarId;
                        }
-                       if ((showCustomAvatars == ShowCustomAvatars.FOLLOWED) && currentSone.hasFriend(remoteSone.getId())) {
-                               return avatarId;
+                       if (showCustomAvatars == ShowCustomAvatars.FOLLOWED) {
+                               return currentSone.hasFriend(remoteSone.getId()) ? avatarId : null;
                        }
                        Trust trust = core.getTrust(currentSone, remoteSone);
                        if (trust == null) {
@@ -83,7 +90,7 @@ public class ProfileAccessor extends ReflectionAccessor {
                        if ((showCustomAvatars == ShowCustomAvatars.MANUALLY_TRUSTED) && (trust.getExplicit() != null) && (trust.getExplicit() > 0)) {
                                return avatarId;
                        }
-                       if ((showCustomAvatars == ShowCustomAvatars.TRUSTED) && ((trust.getExplicit() != null) && (trust.getExplicit() > 0)) || ((trust.getImplicit() != null) && (trust.getImplicit() > 0))) {
+                       if ((showCustomAvatars == ShowCustomAvatars.TRUSTED) && (((trust.getExplicit() != null) && (trust.getExplicit() > 0)) || ((trust.getImplicit() != null) && (trust.getImplicit() > 0)))) {
                                return avatarId;
                        }
                        return null;
index 24bcfd6..7b89713 100644 (file)
@@ -58,7 +58,7 @@ public class ReplyAccessor extends ReflectionAccessor {
                        Sone currentSone = (Sone) templateContext.get("currentSone");
                        return (currentSone != null) && (currentSone.isLikedReplyId(reply.getId()));
                } else if (member.equals("new")) {
-                       return core.isNewReply(reply.getId());
+                       return !reply.isKnown();
                } else if (member.equals("loaded")) {
                        return reply.getSone() != null;
                }
index ead6066..c134fc0 100644 (file)
@@ -21,9 +21,9 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import net.pterodactylus.sone.core.Core;
-import net.pterodactylus.sone.core.Core.SoneStatus;
 import net.pterodactylus.sone.data.Profile;
 import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.data.Sone.SoneStatus;
 import net.pterodactylus.sone.freenet.wot.Trust;
 import net.pterodactylus.sone.web.WebInterface;
 import net.pterodactylus.sone.web.ajax.GetTimesAjaxPage;
@@ -86,17 +86,17 @@ public class SoneAccessor extends ReflectionAccessor {
                } else if (member.equals("modified")) {
                        return core.isModifiedSone(sone);
                } else if (member.equals("status")) {
-                       return core.getSoneStatus(sone);
+                       return sone.getStatus();
                } else if (member.equals("unknown")) {
-                       return core.getSoneStatus(sone) == SoneStatus.unknown;
+                       return sone.getStatus() == SoneStatus.unknown;
                } else if (member.equals("idle")) {
-                       return core.getSoneStatus(sone) == SoneStatus.idle;
+                       return sone.getStatus() == SoneStatus.idle;
                } else if (member.equals("inserting")) {
-                       return core.getSoneStatus(sone) == SoneStatus.inserting;
+                       return sone.getStatus() == SoneStatus.inserting;
                } else if (member.equals("downloading")) {
-                       return core.getSoneStatus(sone) == SoneStatus.downloading;
+                       return sone.getStatus() == SoneStatus.downloading;
                } else if (member.equals("new")) {
-                       return core.isNewSone(sone.getId());
+                       return !sone.isKnown();
                } else if (member.equals("locked")) {
                        return core.isLocked(sone);
                } else if (member.equals("lastUpdatedText")) {
index 6ed5667..f32a47d 100644 (file)
@@ -91,7 +91,7 @@ public class KnownSonesPage extends SoneTemplatePage {
                                 */
                                @Override
                                public boolean filterObject(Sone sone) {
-                                       return webInterface.getCore().isNewSone(sone.getId());
+                                       return !sone.isKnown();
                                }
                        });
                } else if ("not-new".equals(filter)) {
@@ -101,7 +101,7 @@ public class KnownSonesPage extends SoneTemplatePage {
                                 */
                                @Override
                                public boolean filterObject(Sone sone) {
-                                       return !webInterface.getCore().isNewSone(sone.getId());
+                                       return sone.isKnown();
                                }
                        });
                }
diff --git a/src/main/java/net/pterodactylus/sone/web/NewPage.java b/src/main/java/net/pterodactylus/sone/web/NewPage.java
new file mode 100644 (file)
index 0000000..c7281e3
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Sone - NewPage.java - Copyright © 2012 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.web;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.notify.ListNotificationFilters;
+import net.pterodactylus.sone.web.page.FreenetRequest;
+import net.pterodactylus.util.collection.Pagination;
+import net.pterodactylus.util.number.Numbers;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+
+/**
+ * Page that displays all new posts and replies. The posts are filtered using
+ * {@link ListNotificationFilters#filterPosts(java.util.Collection, net.pterodactylus.sone.data.Sone)}
+ * and sorted by time.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class NewPage extends SoneTemplatePage {
+
+       /**
+        * Creates a new “new posts and replies” page.
+        *
+        * @param template
+        *            The template to render
+        * @param webInterface
+        *            The Sone web interface
+        */
+       public NewPage(Template template, WebInterface webInterface) {
+               super("new.html", template, "Page.New.Title", webInterface);
+       }
+
+       //
+       // SONETEMPLATEPAGE METHODS
+       //
+
+       /**
+        * {@inherit}
+        */
+       @Override
+       protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
+               super.processTemplate(request, templateContext);
+
+               /* collect new elements from notifications. */
+               Set<Post> posts = webInterface.getNewPosts();
+               for (PostReply reply : webInterface.getNewReplies()) {
+                       posts.add(reply.getPost());
+               }
+
+               /* filter and sort them. */
+               List<Post> sortedPosts = ListNotificationFilters.filterPosts(new ArrayList<Post>(posts), webInterface.getCurrentSone(request.getToadletContext(), false));
+               Collections.sort(sortedPosts, Post.TIME_COMPARATOR);
+
+               /* paginate them. */
+               Pagination<Post> pagination = new Pagination<Post>(sortedPosts, webInterface.getCore().getPreferences().getPostsPerPage()).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
+               templateContext.set("pagination", pagination);
+               templateContext.set("posts", pagination.getItems());
+       }
+
+}
index 832f9d9..6e10b24 100644 (file)
@@ -67,6 +67,7 @@ public class SearchPage extends SoneTemplatePage {
        /** Short-term cache. */
        private final Cache<List<Phrase>, Set<Hit<Post>>> hitCache = new MemoryCache<List<Phrase>, Set<Hit<Post>>>(new ValueRetriever<List<Phrase>, Set<Hit<Post>>>() {
 
+               @Override
                @SuppressWarnings("synthetic-access")
                public CacheItem<Set<Hit<Post>>> retrieve(List<Phrase> phrases) throws CacheException {
                        Set<Post> posts = new HashSet<Post>();
index a007222..b1c61bb 100644 (file)
@@ -138,9 +138,9 @@ import net.pterodactylus.util.web.RedirectPage;
 import net.pterodactylus.util.web.StaticPage;
 import net.pterodactylus.util.web.TemplatePage;
 import freenet.clients.http.SessionManager;
+import freenet.clients.http.SessionManager.Session;
 import freenet.clients.http.ToadletContainer;
 import freenet.clients.http.ToadletContext;
-import freenet.clients.http.SessionManager.Session;
 import freenet.l10n.BaseL10n;
 import freenet.support.api.HTTPRequest;
 
@@ -243,7 +243,7 @@ public class WebInterface implements CoreListener {
                templateContextFactory.addFilter("html", new HtmlFilter());
                templateContextFactory.addFilter("replace", new ReplaceFilter());
                templateContextFactory.addFilter("store", new StoreFilter());
-               templateContextFactory.addFilter("l10n", new L10nFilter(getL10n()));
+               templateContextFactory.addFilter("l10n", new L10nFilter(this));
                templateContextFactory.addFilter("substring", new SubstringFilter());
                templateContextFactory.addFilter("xml", new XmlFilter());
                templateContextFactory.addFilter("change", new RequestChangeFilter());
@@ -583,6 +583,7 @@ public class WebInterface implements CoreListener {
                Template emptyTemplate = TemplateParser.parse(new StringReader(""));
                Template loginTemplate = TemplateParser.parse(createReader("/templates/login.html"));
                Template indexTemplate = TemplateParser.parse(createReader("/templates/index.html"));
+               Template newTemplate = TemplateParser.parse(createReader("/templates/new.html"));
                Template knownSonesTemplate = TemplateParser.parse(createReader("/templates/knownSones.html"));
                Template createSoneTemplate = TemplateParser.parse(createReader("/templates/createSone.html"));
                Template createPostTemplate = TemplateParser.parse(createReader("/templates/createPost.html"));
@@ -613,6 +614,7 @@ public class WebInterface implements CoreListener {
                PageToadletFactory pageToadletFactory = new PageToadletFactory(sonePlugin.pluginRespirator().getHLSimpleClient(), "/Sone/");
                pageToadlets.add(pageToadletFactory.createPageToadlet(new RedirectPage<FreenetRequest>("", "index.html")));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new IndexPage(indexTemplate, this), "Index"));
+               pageToadlets.add(pageToadletFactory.createPageToadlet(new NewPage(newTemplate, this), "New"));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateSonePage(createSoneTemplate, this), "CreateSone"));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new KnownSonesPage(knownSonesTemplate, this), "KnownSones"));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new EditProfilePage(editProfileTemplate, this), "EditProfile"));
@@ -888,7 +890,7 @@ public class WebInterface implements CoreListener {
                if (!getMentionedSones(reply.getText()).isEmpty()) {
                        boolean isMentioned = false;
                        for (PostReply existingReply : getCore().getReplies(reply.getPost())) {
-                               isMentioned |= getCore().isNewReply(reply.getId()) && !getMentionedSones(existingReply.getText()).isEmpty();
+                               isMentioned |= !reply.isKnown() && !getMentionedSones(existingReply.getText()).isEmpty();
                        }
                        if (!isMentioned) {
                                mentionNotification.remove(reply.getPost());
index 1f23e4a..16bb133 100644 (file)
@@ -177,7 +177,7 @@ public class GetStatusAjaxPage extends JsonPage {
                jsonSone.put("id", sone.getId());
                jsonSone.put("name", SoneAccessor.getNiceName(sone));
                jsonSone.put("local", sone.getInsertUri() != null);
-               jsonSone.put("status", webInterface.getCore().getSoneStatus(sone).name());
+               jsonSone.put("status", sone.getStatus().name());
                jsonSone.put("modified", webInterface.getCore().isModifiedSone(sone));
                jsonSone.put("locked", webInterface.getCore().isLocked(sone));
                jsonSone.put("lastUpdatedUnknown", sone.getTime() == 0);
index 4ee3b99..7c3abdb 100644 (file)
@@ -28,8 +28,8 @@ import net.pterodactylus.util.json.JsonObject;
 import net.pterodactylus.util.json.JsonUtils;
 import net.pterodactylus.util.web.Page;
 import net.pterodactylus.util.web.Response;
-import freenet.clients.http.ToadletContext;
 import freenet.clients.http.SessionManager.Session;
+import freenet.clients.http.ToadletContext;
 
 /**
  * A JSON page is a specialized {@link Page} that will always return a JSON
diff --git a/src/main/resources/i18n/sone.de.properties b/src/main/resources/i18n/sone.de.properties
new file mode 100644 (file)
index 0000000..d4e4fc3
--- /dev/null
@@ -0,0 +1,448 @@
+Navigation.Menu.Sone.Name=Sone
+Navigation.Menu.Sone.Tooltip=Soziales Netzwerk in Freenet
+Navigation.Menu.Sone.Item.Login.Name=Anmelden
+Navigation.Menu.Sone.Item.Login.Tooltip=In Ihre Sone einloggen
+Navigation.Menu.Sone.Item.Index.Name=Ihre Sone
+Navigation.Menu.Sone.Item.Index.Tooltip=Zeigt Ihre Sone an
+Navigation.Menu.Sone.Item.New.Name=Neue Nachrichten und Antworten
+Navigation.Menu.Sone.Item.New.Tooltip=Zeigt neue Nachrichten und Antworten an
+Navigation.Menu.Sone.Item.CreateSone.Name=Sone anlegen
+Navigation.Menu.Sone.Item.CreateSone.Tooltip=Erstellt eine neue Sone
+Navigation.Menu.Sone.Item.KnownSones.Name=Bekannte Sones
+Navigation.Menu.Sone.Item.KnownSones.Tooltip=Zeigt alle bekannten Sones an
+Navigation.Menu.Sone.Item.Bookmarks.Name=Favoriten
+Navigation.Menu.Sone.Item.Bookmarks.Tooltip=Zeigt ihre Lieblingsnachrichten an
+Navigation.Menu.Sone.Item.EditProfile.Name=Profil bearbeiten
+Navigation.Menu.Sone.Item.EditProfile.Tooltip=Bearbeitet das Profil Ihrer Sone
+Navigation.Menu.Sone.Item.ImageBrowser.Name=Bilder
+Navigation.Menu.Sone.Item.ImageBrowser.Tooltip=Verwaltet Ihre Bilder
+Navigation.Menu.Sone.Item.DeleteSone.Name=Sone löschen
+Navigation.Menu.Sone.Item.DeleteSone.Tooltip=Löscht die aktuelle Sone
+Navigation.Menu.Sone.Item.Logout.Name=Abmelden
+Navigation.Menu.Sone.Item.Logout.Tooltip=Meldet die aktuelle Sone ab
+Navigation.Menu.Sone.Item.Options.Name=Optionen
+Navigation.Menu.Sone.Item.Options.Tooltip=Konfiguriert Sone
+Navigation.Menu.Sone.Item.Rescue.Name=Sonerettung
+Navigation.Menu.Sone.Item.Rescue.Tooltip=Rettet Ihre Sone
+Navigation.Menu.Sone.Item.About.Name=Über
+Navigation.Menu.Sone.Item.About.Tooltip=Informationen über Sone
+
+Page.About.Title=Über  - Sone
+Page.About.Page.Title=Über
+Page.About.Flattr.Description=Wenn Sie Sone mögen und sich gerne bei mir dafür erkenntlichen zeigen möchten, können Sie einfach den Flattr-Button benutzen, den Sie am unteren Rand jeder Seite finden. Flattr ist eine nicht anonyme Seite für „Micropayment“, die ein bisschen wie ein Klingelbeutel funktioniert und für jeden User die monatlichen Ausgaben deckelt (mindestens jedoch 2 €). Mehr Informationen erhalten Sie auf {link}flattr.com{/link}.
+Page.About.Homepage.Title=Homepage
+Page.About.Homepage.Description=Mehr Informationen und den Sourcecode von Sone gibt es auf der {link}Sone Homepage{/link}.
+Page.About.License.Title=Lizenz
+
+Page.Options.Title=Optionen - Sone
+Page.Options.Page.Title=Optionen
+Page.Options.Page.Description=Diese Optionen beeinflussen das Laufzeitverhalten von Sone.
+Page.Options.Section.SoneSpecificOptions.Title=Sone-spezifische Optionen
+Page.Options.Section.SoneSpecificOptions.NotLoggedIn=Diese Optionen sind nur verfügbar, wenn Sie {link}angemeldet{/link} sind.
+Page.Options.Section.SoneSpecificOptions.LoggedIn=Diese Optionen sind nur verfügbar, wenn Sie angemeldet sind, und gelten nur für die angemeldete Sone.
+Page.Options.Option.AutoFollow.Description=Wenn eine neue Sone gefunden wird, automatisch folgen. Bitte beachten Sie dabei, dass nur Sones gefolgt wird, die nach der Aktivierung dieser Option gefunden werden!
+Page.Options.Option.EnableSoneInsertNotifications.Description=Zeige Benachrichtigungen an, wenn Ihre Sone hochgeladen wird, oder das Hochladen beendet wurde.
+Page.Options.Option.ShowNotificationNewSones.Description=Zeige Benachrichtigungen für neue Sones.
+Page.Options.Option.ShowNotificationNewPosts.Description=Zeige Benachrichtigungen für neue Nachrichten.
+Page.Options.Option.ShowNotificationNewReplies.Description=Zeige Benachrichtigungen für neue Antworten.
+Page.Options.Section.AvatarOptions.Title=Avataroptionen
+Page.Options.Option.ShowAvatars.Description=Abhängig von der ausgewählten Option können Sie hier benutzerdefinierte Avatare deaktiveren. Wenn ein benutzerdefinierter Avatar unterdrückt wird, wird dafür der normale generierte Avatar angezeigt.
+Page.Options.Option.ShowAvatars.Never.Description=Niemals benutzerdefinierte Avatare anzeigen.
+Page.Options.Option.ShowAvatars.Followed.Description=Nur benutzerdefinierte Avatare von Sones, denen Sie folgen, anzeigen.
+Page.Options.Option.ShowAvatars.ManuallyTrusted.Description=Nur benutzerdefinierte Avatare von Sones, denen Sie manuell einen Vertrauenswert von mehr als 0 zugewiesen haben, anzeigen.
+Page.Options.Option.ShowAvatars.Trusted.Description=Nur benutzerdefinierte Avatare von Sones, die einen berechneten Vertrauenswert von mehr als 0 haben, anzeigen.
+Page.Options.Option.ShowAvatars.Always.Description=Immer benutzerdefinierte Avatare anzeigen. Warnung: Benutzerdefinierte Avatare können beliebiges Bildmaterial enthalten! 
+Page.Options.Section.RuntimeOptions.Title=Laufzeitverhalten
+Page.Options.Option.InsertionDelay.Description=Anzahl der Sekunden, die vor dem Hochladen einer Sone nach einer Änderung gewartet wird.
+Page.Options.Option.PostsPerPage.Description=Anzahl der Nachrichten pro Seite.
+Page.Options.Option.CharactersPerPost.Description=Die Anzahl der Zeichen, die eine Nachricht enthalten muss, damit sie gekürzt angezeigt wird (-1 für „nie kürzen“). Die Anzahl der tatsächlich angezeigten Zeichen wird in der nächsten Option konfiguriert.
+Page.Options.Option.PostCutOffLength.Description=Die Anzahl der Zeichen, die von einer gekürzten Nachricht sichtbar sind (siehe Option hierüber).
+Page.Options.Option.RequireFullAccess.Description=Zugriff auf Sone für alle Rechner, die keinen vollen Zugriff haben, unterbinden.
+Page.Options.Section.TrustOptions.Title=Vertrauenseinstellungen
+Page.Options.Option.PositiveTrust.Description=Die Menge an positivem Vertrauen, die bei einem Klick auf den Haken unter einer Nachricht zugewiesen werden soll.
+Page.Options.Option.NegativeTrust.Description=Die Menge an negativem Vertrauen, die bei einem Klick auf das rote X unter einer Nachricht zugewiesen werden soll. Dieser Wert sollte negativ sein.
+Page.Options.Option.TrustComment.Description=Der Kommentar, der im Web of Trust für Ihre Zuweisung angezeigt werden soll.
+Page.Options.Section.FcpOptions.Title=FCP-Schnittstellenoptionen
+Page.Options.Option.FcpInterfaceActive.Description=Die FCP-Schnittstelle aktivieren, um anderen Plugins und Programmen den Zugriff auf Ihr Sone-Plugin zu ermöglichen.
+Page.Options.Option.FcpFullAccessRequired.Description=FCP-Verbindungen nur von „erlaubten Hosts“ erlauben (siehe {link}Knoten-Konfiguration, Abschnitt “FCP”{/link}).
+Page.Options.Option.FcpFullAccessRequired.Value.No=Nein
+Page.Options.Option.FcpFullAccessRequired.Value.Writing=Für Schreibzugriffe
+Page.Options.Option.FcpFullAccessRequired.Value.Always=Immer
+Page.Options.Section.Cleaning.Title=Aufräumen
+Page.Options.Option.ClearOnNextRestart.Description=Setzt die Konfiguration des Sone-Plugins beim nächsten Start zurück. Vorsicht: {strong}Alle Informationen Ihrer Sones werden gelöscht{/strong}, also stellen Sie bitte sicher, dass Sie die notwendigen Sicherungen angefertigt haben! Damit diese Option aktiv wird, muss auch die folgende Option aktiviert werden.
+Page.Options.Option.ReallyClearOnNextRestart.Description=Diese Option muss auf „ja“ gestellt werden, wenn Sie wirklich {strong}wirklich{/strong} sämtliche Informationen des Sone-Plugins beim nächsten Start entfernen möchten.
+Page.Options.Warnings.ValueNotChanged=Diese Option wurde nicht geändert, weil Sie einen ungültigen Wert angegeben haben.
+Page.Options.Button.Save=Speichern
+
+Page.Login.Title=Anmelden - Sone
+Page.Login.Page.Title=Anmelden
+Page.Login.Label.SelectSone=Sone auswählen:
+Page.Login.Option.NoSone=Sone auswählen…
+
+Page.Login.CreateSone.Title=Sone anlegen
+
+Page.CreateSone.Title=Sone anlegen - Sone
+
+Page.DeleteSone.Title=Sone löschen - Sone
+Page.DeleteSone.Page.Title=Sone „{sone}“ löschen?
+Page.DeleteSone.Page.Description=Ihre Sone wird nicht wirklich aus Freenet gelöscht, weil das nicht möglich ist; es wird lediglich die Verbindung zum „Web of Trust“ getrennt.
+Page.DeleteSone.Button.Yes=Ja, löschen.
+Page.DeleteSone.Button.No=Nein, nicht löschen.
+
+Page.Index.Title=Ihre Sone - Sone
+Page.Index.Label.Text=Ihre Nachricht:
+Page.Index.Label.Sender=Absender:
+Page.Index.Button.Post=Abschicken!
+Page.Index.PostList.Title=Nachrichtenliste
+Page.Index.PostList.Text.NoPostYet=Bisher hat noch niemand etwas geschrieben. Sie sollten sofort damit anfangen!
+
+Page.New.Title=Neue Nachrichten und Antworten - Sone
+Page.New.Page.Title=Neue Nachrichten und Antworten
+Page.New.NothingNew=Im Moment gibt es nichts Neues.
+
+Page.KnownSones.Title=Bekannte Sones - Sone
+Page.KnownSones.Page.Title=Bekannte Sones
+Page.KnownSones.Text.NoKnownSones=Für die aktuellen Filterkriterien können keine Sones gefunden werden.
+Page.KnownSones.Label.Sort=Sortieren:
+Page.KnownSones.Label.FilterSones=Sones filtern:
+Page.KnownSones.Sort.Field.Name=Name
+Page.KnownSones.Sort.Field.LastActivity=Letzte Aktivität
+Page.KnownSones.Sort.Field.Posts=Anzahl der Nachrichten
+Page.KnownSones.Sort.Field.Images=Anzahl der Bilder
+Page.KnownSones.Sort.Order.Ascending=Aufsteigend
+Page.KnownSones.Sort.Order.Descending=Absteigend
+Page.KnownSones.Filter.Followed=Nur gefolgte Sones anzeigen
+Page.KnownSones.Filter.NotFollowed=Gefolgte Sones nicht anzeigen
+Page.KnownSones.Filter.New=Nur neue Sones anzeigen
+Page.KnownSones.Filter.NotNew=Neue Sones nicht anzeigen
+Page.KnownSones.Button.Apply=Anwenden
+Page.KnownSones.Button.FollowAllSones=Allen Sones auf dieser Seite folgen
+Page.KnownSones.Button.UnfollowAllSones=Alle Sones auf dieser Seite entfolgen
+
+Page.EditProfile.Title=Profil bearbeiten - Sone
+Page.EditProfile.Page.Title=Profil bearbeiten
+Page.EditProfile.Page.Description=Auf dieser Seite können Sie Ihr Profile bearbeiten.
+Page.EditProfile.Page.Hint.Optionality=Bitte denken Sie daran: Jedes einzelne Feld auf dieser Seite ist optional! Keine der Angaben ist zwingend! Alles, was Sie hier angeben, wird möglicherweise für eine lange Zeit in Freenet gespeichert bleiben.
+Page.EditProfile.Label.FirstName=Vorname:
+Page.EditProfile.Label.MiddleName=Zweiter Vorname:
+Page.EditProfile.Label.LastName=Nachname:
+Page.EditProfile.Birthday.Title=Geburtstag
+Page.EditProfile.Birthday.Label.Day=Tag:
+Page.EditProfile.Birthday.Label.Month=Monat:
+Page.EditProfile.Birthday.Label.Year=Jahr:
+Page.EditProfile.Avatar.Title=Avatar
+Page.EditProfile.Avatar.Description=Sie können eines Ihrer hochgeladenen Bilder als Avatar auswählen. Es sollte nicht größer als 64×64 Pixel, da das die größte Größe ist, die bei anderen Leuten im Webinterface angezeigt wird. (Bei Ihnen wird im Kopf der Seite eine Version in 80×80 Pixeln angezeigt.)
+Page.EditProfile.Avatar.Delete=Kein Avatar
+Page.EditProfile.Fields.Title=Benutzerdefinierte Felder
+Page.EditProfile.Fields.Description=Sie können Ihrem Profil eigene Felder hinzufügen. Diese Felder können alles mögliche enthalten. Bedenken Sie jedoch, dass, wenn es um Anonymität geht, weniger manchmal mehr ist.
+Page.EditProfile.Fields.Button.Edit=bearbeiten
+Page.EditProfile.Fields.Button.MoveUp=nach oben
+Page.EditProfile.Fields.Button.MoveDown=nach unten
+Page.EditProfile.Fields.Button.Delete=löschen
+Page.EditProfile.Fields.Button.ReallyDelete=wirklich löschen
+Page.EditProfile.Fields.AddField.Title=Feld hinzufügen
+Page.EditProfile.Fields.AddField.Label.Name=Name:
+Page.EditProfile.Fields.AddField.Button.AddField=Feld hinzufügen
+Page.EditProfile.Button.Save=Profil speichern
+Page.EditProfile.Error.DuplicateFieldName=Das Feld „{fieldName}“ existiert bereits.
+
+Page.EditProfileField.Title=Benutzerdefiniertes Feld bearbeiten - Sone
+Page.EditProfileField.Page.Title=Benutzerdefiniertes Feld bearbeiten
+Page.EditProfileField.Text=Bitte geben Sie einen neuen Namen für dieses benutzerdefinierte Feld ein.
+Page.EditProfileField.Error.DuplicateFieldName=Der von Ihnen eingegebene Feldname existiert bereits.
+Page.EditProfileField.Button.Save=Ändern
+Page.EditProfileField.Button.Reset=Aten Namen wiederherstellen
+Page.EditProfileField.Button.Cancel=Namen nicht ändern
+
+Page.DeleteProfileField.Title=Benutzerdefiniertes Feld löschen - Sone
+Page.DeleteProfileField.Page.Title=Benutzerdefiniertes Feld löschen
+Page.DeleteProfileField.Text=Möchten Sie dieses Feld wirklich löschen?
+Page.DeleteProfileField.Button.Yes=Ja, löschen
+Page.DeleteProfileField.Button.No=Nein, nicht löschen
+
+Page.CreatePost.Title=Nachricht schreiben - Sone
+Page.CreatePost.Page.Title=Nachricht schreiben
+Page.CreatePost.Label.Text=Inhalt der Nachricht:
+Page.CreatePost.Button.Post=Abschicken!
+Page.CreatePost.Error.EmptyText=Sie haben leider keinen Text eingegeben. Sie sollten wirklich etwas mehr schreiben!
+
+Page.CreateReply.Title=Antwort schreiben - Sone
+Page.CreateReply.Page.Title=Antwort schreiben
+Page.CreateReply.Error.EmptyText=Sie haben leider keinen Text eingegeben. Sie sollten wirklich etwas mehr schreiben!
+Page.CreateReply.Label.Text=Inhalt der Antwort:
+Page.CreateReply.Button.Post=Abschicken!
+
+Page.ViewSone.Title=Sone anzeigen - Sone
+Page.ViewSone.Page.TitleWithoutSone=Unbekannte Sone anzeigen
+Page.ViewSone.NoSone.Description=Momentan ist keine Sone mit der ID {sone} bekannt. Wenn Sie eine bestimmte Sone gesucht haben, vergewissern Sie sich bitte, dass Sie in Ihrem „Web of Trust“ sichtbar ist:
+Page.ViewSone.UnknownSone.Description=Diese Sone wurde noch nicht herunter geladen. Bitte versuchen Sie es in Kürze nochmal.
+Page.ViewSone.UnknownSone.LinkToWebOfTrust=Auch, wenn diese Sone noch nicht herunter geladen wurde, so ist vielleicht ihr „Web of Trust“ Profil bereits verfügbar:
+Page.ViewSone.WriteAMessage=Sie können hier eine Nachricht an diese Sone schreiben. Bitte beachten Sie, dass diese Nachricht für alle Sones sichtbar ist!
+Page.ViewSone.PostList.Title=Nachrichten von {sone}
+Page.ViewSone.PostList.Text.NoPostYet=Diese Sone hat noch nichts geschrieben.
+Page.ViewSone.Profile.Title=Profil
+Page.ViewSone.Profile.Label.Name=Name
+Page.ViewSone.Profile.Label.Albums=Alben
+Page.ViewSone.Profile.Albums.Text.All=Alle Alben
+Page.ViewSone.Profile.Name.WoTLink=„Web of Trust“ Profil
+Page.ViewSone.Replies.Title=Nachrichten, auf die {sone} geantwortet hat
+
+Page.ViewPost.Title=Nachricht anzeigen - Sone
+Page.ViewPost.Page.Title=Nachricht von {sone} anzeigen
+Page.ViewPost.Page.TitleUnknownSone=Unbekannte Nachricht anzeigen
+Page.ViewPost.Text.UnknownPost=Diese Nachricht wurde noch nicht herunter geladen.
+
+Page.Like.Title=Nachricht gefällt - Sone
+Page.Unlike.Title=Nachricht gefällt nicht - Sone
+
+Page.DeletePost.Title=Nachricht löschen - Sone
+Page.DeletePost.Page.Title=Nachricht löschen
+Page.DeletePost.Text.PostWillBeGone=Diese Nachricht wird aus Ihrer Sone gelöscht. Es ist jedoch technisch nicht möglich, sie auch aus Freenet zu entfernen; ältere Versionen Ihrer Sone werden diese Nachricht immer enthalten.
+Page.DeletePost.Button.Yes=Ja, löschen.
+Page.DeletePost.Button.No=Nein, nicht löschen.
+
+Page.DeleteReply.Title=Antwort löschen - Sone
+Page.DeleteReply.Page.Title=Antwort löschen
+Page.DeleteReply.Text.PostWillBeGone=Diese Antwort wird aus Ihrer Sone gelöscht. Es ist jedoch technisch nicht möglich, sie auch aus Freenet zu entfernen; ältere Versionen Ihrer Sone werden diese Antwort immer enthalten.
+Page.DeleteReply.Button.Yes=Ja, löschen.
+Page.DeleteReply.Button.No=Nein, nicht löschen.
+
+Page.LockSone.Title=Sone sperren - Sone
+
+Page.UnlockSone.Title=Sone entsperren - Sone
+
+Page.FollowSone.Title=Sone folgen - Sone
+
+Page.UnfollowSone.Title=Sone entfolgen - Sone
+
+Page.ImageBrowser.Title=Bildergallerie - Sone
+Page.ImageBrowser.Album.Title=Album “{album}”
+Page.ImageBrowser.Album.Error.NotFound.Text=Das gewünschte Album konnte nicht gefunden werden. Es ist möglich, dass es noch nicht herunter geladen oder bereits gelöscht wurde.
+Page.ImageBrowser.Sone.Title=Alben von {sone}
+Page.ImageBrowser.Sone.Error.NotFound.Text=Die gewünschte Sone konnte nicht gefunden werden. Es ist möglich, dass sie noch nicht herunter geladen wurde.
+Page.ImageBrowser.Header.Albums=Alben
+Page.ImageBrowser.Header.Images=Bilder
+Page.ImageBrowser.Link.All=Alle Sones
+Page.ImageBrowser.CreateAlbum.Button.CreateAlbum=Album anlegen
+Page.ImageBrowser.Album.Edit.Title=Album bearbeiten
+Page.ImageBrowser.Album.Delete.Title=Album löschen
+Page.ImageBrowser.Album.Label.AlbumImage=Albumbild:
+Page.ImageBrowser.Album.Label.Title=Titel:
+Page.ImageBrowser.Album.Label.Description=Beschreibung:
+Page.ImageBrowser.Album.AlbumImage.Choose=Albumbild auswählen…
+Page.ImageBrowser.Album.Button.Save=Album speichern
+Page.ImageBrowser.Album.Button.Delete=Album löschen
+Page.ImageBrowser.Image.Edit.Title=Bild bearbeiten
+Page.ImageBrowser.Image.Title.Label=Titel:
+Page.ImageBrowser.Image.Description.Label=Beschreibung:
+Page.ImageBrowser.Image.Button.MoveLeft=◀
+Page.ImageBrowser.Image.Button.Save=Bild speichern
+Page.ImageBrowser.Image.Button.MoveRight=►
+Page.ImageBrowser.Image.Delete.Title=Bild löschen
+Page.ImageBrowser.Image.Button.Delete=Bild löschen
+
+Page.CreateAlbum.Title=Album anlegen - Sone
+Page.CreateAlbum.Page.Title=Album anlegen
+Page.CreateAlbum.Error.NameMissing=Sie haben keinen Namen für Ihr neues Album angegeben.
+
+Page.UploadImage.Title=Bild hochladen - Sone
+Page.UploadImage.Error.InvalidImage=Das Bild, welches Sie hoch geladen haben, konnte nicht gelesen werden. Bitte laden Sie nur JPEG- (*.jpg, *.jpeg) oder PNG-Bilder (*.png) hoch!
+
+Page.EditImage.Title=Bild bearbeiten - Sone
+
+Page.DeleteImage.Title=Bild löschen - Sone
+Page.DeleteImage.Page.Title=Bild löschen
+Page.DeleteImage.Text.ImageWillBeGone=Das Bild „{image}“ wird aus Ihrem Album „{album}“ gelöscht. Wenn das Bild bereits in Freenet hoch geladen wurde, kann es von dort nicht mehr entfernt werden. Wollen Sie dieses Bild wirklich löschen?
+Page.DeleteImage.Button.Yes=Ja, Bild löschen.
+Page.DeleteImage.Button.No=Nein, Bild nicht löschen.
+
+Page.EditAlbum.Title=Album bearbeiten - Sone
+
+Page.DeleteAlbum.Title=Album löschen - Sone
+Page.DeleteAlbum.Page.Title=Album löschen
+Page.DeleteAlbum.Text.AlbumWillBeGone=Ihr Album „{title}“ wird gelöscht. Möchten Sie fortfahren?
+Page.DeleteAlbum.Button.Yes=Ja, Album löschen.
+Page.DeleteAlbum.Button.No=Nein, Album nicht löschen.
+
+Page.Trust.Title=Sone vertrauen - Sone
+
+Page.Distrust.Title=Sone misstrauen - Sone
+
+Page.Untrust.Title=Sone nicht vertrauen - Sone
+
+Page.MarkAsKnown.Title=Als gelesen markieren - Sone
+
+Page.Bookmark.Title=Als Favorit markieren - Sone
+Page.Unbookmark.Title=Favoritenmarkierung entfernen - Sone
+Page.Bookmarks.Title=Favoriten - Sone
+Page.Bookmarks.Page.Title=Favoriten
+Page.Bookmarks.Text.NoBookmarks=Sie haben bisher keine Nachrichten zu Ihren Favoriten erklärt. Sie können eine Nachricht zu einem Favoriten erklären, indem Sie den Stern unter der Nachricht anklicken.
+Page.Bookmarks.Text.PostsNotLoaded=Einige Ihrer Favoriten können nicht angezeigt werden, weil sie noch nicht geladen wurden. Das kann passieren, wenn Sie Sone kürzlich erst neu gestartet haben, oder wenn die Nachricht gelöscht wurde. Wenn Sie sich sicher sind, dass alle favorisierten Nachrichten, die jetzt nicht angezeigt werden, nicht mehr existieren, können Sie sie {link}aus Ihren Favoriten entfernen{/link}.
+
+Page.Search.Title=Suchen - Sone
+Page.Search.Page.Title=Suchergebnisse
+Page.Search.Text.SoneHits=Diese Sones passen auf Ihre Suchbegriffe.
+Page.Search.Text.PostHits=Dises Nachrichten passen auf Ihre Suchbegriffe.
+Page.Search.Text.NoHits=Keine Sones oder Nachrichten passten auf Ihre Suchbegriffe.
+
+Page.Rescue.Title=Sone retten - Sone
+Page.Rescue.Page.Title=Sone „{0}“ retten
+Page.Rescue.Text.Description=Die Sonerettung stellt vorherige Versionen Ihrer Sone wieder her. Dieses kann notwendig werden, wenn die Konfiguration verloren geht.
+Page.Rescue.Text.Procedure=Die Sonerettung lädt die letzte hoch geladene Version Ihrer Sone. Wenn die Version erfolgreich geladen wurde, können Sie sie in aller Ruhe inspizieren, z. B. in einem zweiten Browser-Tab, und bei Gefallen können Sie einfach Ihre Sone entsperren; die zuletzt geladene Version wird dann als aktuelle Version neu hoch geladen. Wenn eine ältere Version geladen werden soll, können Sie der Sonerettung einfach sagen, dass sie die nächstältere Version herunter laden soll.
+Page.Rescue.Text.Fetching=Die Sonerettung versucht gerade, Version {0} Ihrer Sone herunter zu laden.
+Page.Rescue.Text.Fetched=Die Sonerettung hat Version {0} Ihrer Sone herunter geladen. Bitte überprüfen Sie Ihre Nachrichten, Antworten und Ihr Profile. Bei Gefallen können Sie die Sone einfach entsperren.
+Page.Rescue.Text.FetchedLast=Die Sonerettung hat die letzte verfügbare Version Ihrer Sone herunter geladen. Wenn bis jetzt keine Version dabei war, die Sie wiederherstellen möchten, haben Sie jetzt kein Glück.
+Page.Rescue.Text.NotFetched=Die Sonerettung konnte Version {0} Ihrer Sone nicht herunter laden. Bitte versuchen Sie erneut, Version {0} herunter zu laden, oder versuchen Sie die nächstältere Version.
+Page.Rescue.Label.NextEdition=Nächste Version:
+Page.Rescue.Button.Fetch=Version herunter laden
+
+Page.NoPermission.Title=Unberechtigter Zugriff - Sone
+Page.NoPermission.Page.Title=Unberechtigter Zugriff
+Page.NoPermission.Text.NoPermission=Sie haben versucht, etwas zu tun, zu dem Sie nicht berechtigt sind. Bitte unterlassen Sie das, da wir sonst gezwungen sind, Gegenmaßnahmen zu ergreifen!
+
+Page.DismissNotification.Title=Benachrichtigung ausblenden - Sone
+
+Page.WotPluginMissing.Text.WotRequired=Da das „Web of Trust“ ein integraler Bestandteil von Sone ist, muss das „Web of Trust“ Plugin geladen sein, damit Sone funktionieren kann.
+Page.WotPluginMissing.Text.LoadPlugin=Bitte laden Sie das „Web of Trust“ Plugin im {link}plugin manager{/link}.
+
+Page.Logout.Title=Abmelden - Sone
+
+Page.Invalid.Title=Ungültige Aktion ausgeführt - Sone
+Page.Invalid.Page.Title=Ungültige Aktion ausgeführt
+Page.Invalid.Text=Eine ungültige Aktion wurde ausgeführt, oder eine gültige Aktion hatte ungültige Parameter. Bitte kehren Sie zur {link}Hauptseite{/link} zurück und versuchen Sie Ihre Aktion erneut. Wenn der Fehler weiterhin besteht, haben Sie wahrscheinlich einen Programmierfehler gefunden.
+
+View.Search.Button.Search=Suchen
+
+View.CreateSone.Text.WotIdentityRequired=Um eine Sone anzulegen, brauchen Sie eine Identität aus dem {link}„Web of Trust“ Plugin{/link}.
+View.CreateSone.Select.Default=Eine Identität auswählen
+View.CreateSone.Text.NoIdentities=Sie haben keine Identitäten im „Web of Trust“ Plugin. Bitte erstellen Sie im {link}„Web of Trust“ Plugin{/link} eine neue Identität.
+View.CreateSone.Text.NoNonSoneIdentities=Sie haben keine Identitäten im „Web of Trust“ Plugin, die noch nicht mit einer Sone verbunden sind. Benutzen Sie eine der verbleibenden Identitäten, um eine neue Sone anzulegen, oder erstellen Sie im {link}„Web of Trust“ Plugin{/link} eine neue Identität.
+View.CreateSone.Button.Create=Sone anlegen
+View.CreateSone.Text.Error.NoIdentity=Sie haben keine Identität ausgewählt.
+
+View.Sone.Label.LastUpdate=Letzte Aktivität:
+View.Sone.Text.UnknownDate=unbekannt
+View.Sone.Stats.Posts={0,number} {0,choice,0#Nachrichten|1#Nachricht|1<Nachrichten}
+View.Sone.Stats.Replies={0,number} {0,choice,0#Antwort|1#Antwort|1<Antworten}
+View.Sone.Stats.Images={0,number} {0,choice,0#Bilder|1#Bild|1<Bilder}
+View.Sone.Button.UnlockSone=entsperren
+View.Sone.Button.UnlockSone.Tooltip=Diese Version zum Hochladen freigeben
+View.Sone.Button.LockSone=sperren
+View.Sone.Button.LockSone.Tooltip=Verhindert, dass die Sone jetzt hoch geladen wird
+View.Sone.Button.UnfollowSone=entfolgen
+View.Sone.Button.FollowSone=folgen
+View.Sone.Status.Modified=Diese Sone wurde verändert und wartet darauf, hoch geladen zu werden.
+View.Sone.Status.Unknown=Diese Sone wurde noch nicht herunter geladen.
+View.Sone.Status.Idle=Diese Sone wird gerade weder hoch noch herunter geladen.
+View.Sone.Status.Downloading=Diese Sone wird gerade herunter geladen.
+View.Sone.Status.Inserting=Diese Sone wird gerade hoch geladen.
+
+View.SoneMenu.Link.AllAlbums=alle Alben
+
+View.Post.UnknownAuthor=(unbekannt)
+View.Post.WebOfTrustLink=„Web of Trust“ Profil
+View.Post.Permalink=Nachrichtenlink
+View.Post.PermalinkAuthor=Autorenlink
+View.Post.Bookmarks.PostIsBookmarked=Nachricht ist ein Favorit, klicken, um Favoritenmarkierung zu entfernen
+View.Post.Bookmarks.PostIsNotBookmarked=Nachricht ist kein Favorit, klicken, um in Favoriten aufzunehmen
+View.Post.DeleteLink=Löschen
+View.Post.SendReply=Antworten
+View.Post.Reply.DeleteLink=Löschen
+View.Post.LikeLink=Gefällt mir
+View.Post.UnlikeLink=Gefällt mir nicht
+View.Post.ShowSource=Quelltext zeigen
+View.Post.NotDownloaded=Diese Nachricht wurde noch nicht herunter geladen, oder sie wurde bereits gelöscht.
+View.Post.ShowMore=mehr zeigen
+View.Post.ShowLess=weniger zeigen
+
+View.UpdateStatus.Text.ChooseSenderIdentity=Absender wählen
+
+View.Trust.Tooltip.Trust=Dieser Sone vertrauen
+View.Trust.Tooltip.Distrust=Dieser Sone misstrauen
+View.Trust.Tooltip.Untrust=Dieser Sone kein Vertrauen zuweisen
+
+View.CreateAlbum.Title=Album anlegen
+View.CreateAlbum.Label.Name=Name:
+View.CreateAlbum.Label.Description=Beschreibung:
+
+View.UploadImage.Title=Bild hoch laden
+View.UploadImage.Label.Title=Titel:
+View.UploadImage.Label.Description=Beschreibung:
+View.UploadImage.Button.UploadImage=Bild hoch laden
+
+View.Time.InTheFuture=in der Zukunft
+View.Time.AFewSecondsAgo=vor ein paar Sekunden
+View.Time.HalfAMinuteAgo=vor einer halben Minute
+View.Time.AMinuteAgo=vor ungefähr einer Minute
+View.Time.XMinutesAgo=vor ${min} Minuten
+View.Time.HalfAnHourAgo=vor einer halben Stunde
+View.Time.AnHourAgo=vor ungefähr einer Stunde
+View.Time.XHoursAgo=vor ${hour} Stunden
+View.Time.ADayAgo=vor ungefähr einem Tag
+View.Time.XDaysAgo=vor ${day} Tagen
+View.Time.AWeekAgo=vor ungefähr einer Woche
+View.Time.XWeeksAgo=vor ${week} Wochen
+View.Time.AMonthAgo=vor ungefähr einem Monat
+View.Time.XMonthsAgo=vor ${month} Monaten
+View.Time.AYearAgo=vor ungefähr einem Jahr
+View.Time.XYearsAgo=vor ${year} Jahren
+
+WebInterface.DefaultText.StatusUpdate=Was beschäftigt Sie gerade?
+WebInterface.DefaultText.Message=Schreiben Sie eine Nachricht…
+WebInterface.DefaultText.Reply=Schreiben Sie eine Antwort…
+WebInterface.DefaultText.FirstName=Vorname
+WebInterface.DefaultText.MiddleName=Zweiter Vorname
+WebInterface.DefaultText.LastName=Nachname
+WebInterface.DefaultText.BirthDay=Tag
+WebInterface.DefaultText.BirthMonth=Monat
+WebInterface.DefaultText.BirthYear=Jahr
+WebInterface.DefaultText.FieldName=Feldname
+WebInterface.DefaultText.Option.InsertionDelay=Zeit, die vor dem Hochladen einer geänderten Sone gewartet wird (in Sekunden)
+WebInterface.DefaultText.Search=Was suchen Sie?
+WebInterface.DefaultText.CreateAlbum.Name=Albumtitel
+WebInterface.DefaultText.CreateAlbum.Description=Albumbeschreibung
+WebInterface.DefaultText.EditAlbum.Title=Albumtitle
+WebInterface.DefaultText.EditAlbum.Description=Albumbeschreibung
+WebInterface.DefaultText.UploadImage.Title=Bildtitel
+WebInterface.DefaultText.UploadImage.Description=Bildbeschreibung
+WebInterface.DefaultText.EditImage.Title=Bildtitel
+WebInterface.DefaultText.EditImage.Description=Bildbeschreibung
+WebInterface.DefaultText.Option.PostsPerPage=Anzahl der Nachrichten pro Seite
+WebInterface.DefaultText.Option.CharactersPerPost=Anzahl der Zeichen, die eine Nachricht haben muss, damit er gekürzt wird
+WebInterface.DefaultText.Option.PostCutOffLength=Anzahl der Zeichen, die von einer gekürzten Nachricht angezeigt werden 
+WebInterface.DefaultText.Option.PositiveTrust=Der positive Vertrauenswert
+WebInterface.DefaultText.Option.NegativeTrust=Der negative Vertrauenswert
+WebInterface.DefaultText.Option.TrustComment=Der Kommentar für die Vertrauenszuweisung
+WebInterface.Button.Comment=Antworten
+WebInterface.Confirmation.DeletePostButton=Ja, löschen!
+WebInterface.Confirmation.DeleteReplyButton=Ja, löschen!
+WebInterface.SelectBox.Choose=Auswählen…
+WebInterface.SelectBox.Yes=Ja
+WebInterface.SelectBox.No=Nein
+WebInterface.ClickToShow.Replies=Hier klicken, um ausgeblendete Antworten zu zeigen.
+WebInterface.VersionInformation.CurrentVersion=Aktuelle Version:
+WebInterface.VersionInformation.LatestVersion=Neueste Version:
+
+Notification.ClickHereToRead=Hier klicken, um den vollen Text der Benachrichtigung zu lesen.
+Notification.FirstStart.Text=Es scheint, als wäre dies das erste Mal, dass Sie Sone starten. Legen Sie eine neue Sone an und folgen Sie anderen Sones!
+Notification.Startup.Text=Sone startet gerade. Es dauert ein bisschen, bis alle Sones herunter geladen sind. Wenn sie einzelne Sones oder Nachrichten vermissen, gedulden Sie sich bitte ein bisschen, sie werden vermutlich schon sehr bald auftauchen.
+Notification.ConfigNotRead.Text=Die Konfigurationsdatei „sone.properties“ konnte nicht gelesen werden, weil sie vermutlich nicht korrekt geschrieben wurde. Dieses passiert häufig mit Versionen vor 0.3.3, und es gibt nichts, was Sie dagegen tun könnten.
+Notification.Button.Dismiss=Ausblenden
+Notification.NewSone.ShortText=Neue Sones wurden gefunden:
+Notification.NewSone.Text=Neue Sones wurden gefunden:
+Notification.NewPost.ShortText=Neue Nachrichten wurden gefunden.
+Notification.NewPost.Text=Neue Nachrichten von diesen Sones wurden gefunden:
+Notification.NewPost.Button.MarkRead=Als gelesen markieren
+Notification.NewReply.ShortText=Neue Antworten wurden gefunden.
+Notification.NewReply.Text=Neue Antworten auf Nachrichten von diesen Sones wurden gefunden:
+Notification.SoneIsBeingRescued.Text=Diese Sones werden gerade gerettet:
+Notification.SoneRescued.Text=Diese Sones wurden gerettet:
+Notification.SoneRescued.Text.RememberToUnlock=Bitte denken Sie daran, die Nachrichten und Antworten dieser Sone(s) zu kontrollieren und sie danach zu entsperren!
+Notification.LockedSones.Text=Diese Sones sind seit mehr als 5 Minuten gesperrt. Bitte überprüfen Sie, ob diese Sones wirklich gesperrt bleiben sollen:
+Notification.NewVersion.Text=Die Version {version} vom Sone-Plugin wurde gefunden. Sie können diese Version von USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}​ herunter laden.
+Notification.InsertingImages.Text=Diese Bilder werden gerade nach Freenet hoch geladen:
+Notification.InsertedImages.Text=Diese Bilder wurden nach Freenet hoch geladen:
+Notification.ImageInsertFailed.Text=Diese Bilder konnten nicht nach Freenet hoch geladen werden:
+Notification.Mention.ShortText=Sie wurden erwähnt.
+Notification.Mention.Text=Sie wurden in diesen Nachrichten erwähnt:
+Notification.SoneInsert.Duration={0,number} {0,choice,0#Sekunden|1#Sekunde|1<Sekunden}
index c3c1bc1..3fe965e 100644 (file)
@@ -4,6 +4,8 @@ Navigation.Menu.Sone.Item.Login.Name=Login
 Navigation.Menu.Sone.Item.Login.Tooltip=Login to your Sone
 Navigation.Menu.Sone.Item.Index.Name=Your Sone
 Navigation.Menu.Sone.Item.Index.Tooltip=Show your Sone
+Navigation.Menu.Sone.Item.New.Name=New Posts and Replies
+Navigation.Menu.Sone.Item.New.Tooltip=Shows new posts and replies
 Navigation.Menu.Sone.Item.CreateSone.Name=Create Sone
 Navigation.Menu.Sone.Item.CreateSone.Tooltip=Create a new Sone
 Navigation.Menu.Sone.Item.KnownSones.Name=Known Sones
@@ -82,7 +84,7 @@ Page.Login.CreateSone.Title=Create Sone
 Page.CreateSone.Title=Create Sone - Sone
 
 Page.DeleteSone.Title=Delete Sone - Sone
-Page.DeleteSone.Page.Title=Delete Sone “{zone}”?
+Page.DeleteSone.Page.Title=Delete Sone “{sone}”?
 Page.DeleteSone.Page.Description=This will not delete the Sone from Freenet (because that is impossible), it will merely disconnect your web of trust identity from Sone.
 Page.DeleteSone.Button.Yes=Yes, delete.
 Page.DeleteSone.Button.No=No, do not delete.
@@ -94,6 +96,10 @@ Page.Index.Button.Post=Post!
 Page.Index.PostList.Title=Post Feed
 Page.Index.PostList.Text.NoPostYet=Nobody has written any posts yet. You should probably start it right now!
 
+Page.New.Title=New Posts and Replies - Sone
+Page.New.Page.Title=New Posts and Replies
+Page.New.NothingNew=At the moment there’s nothing new.
+
 Page.KnownSones.Title=Known Sones - Sone
 Page.KnownSones.Page.Title=Known Sones
 Page.KnownSones.Text.NoKnownSones=There are currently no known Sones that match the given filter.
@@ -168,7 +174,7 @@ Page.CreateReply.Button.Post=Post Reply!
 
 Page.ViewSone.Title=View Sone - Sone
 Page.ViewSone.Page.TitleWithoutSone=View unknown Sone
-Page.ViewSone.NoSone.Description=There is currently no known Sone with the ID {sone}. If you were looking for a specific Sone, make sure that it is visible in your web of trust!
+Page.ViewSone.NoSone.Description=There is currently no known Sone with the ID {sone}. If you were looking for a specific Sone, make sure that it is visible in your web of trust:
 Page.ViewSone.UnknownSone.Description=This Sone has not yet been retrieved. Please check back in a short time.
 Page.ViewSone.UnknownSone.LinkToWebOfTrust=Even though the Sone is still unknown, its Web of Trust profile might already be available:
 Page.ViewSone.WriteAMessage=You can write a message to this Sone here. Please note that everybody will be able to read this message!
@@ -242,17 +248,17 @@ Page.CreateAlbum.Error.NameMissing=You seem to have forgotten to enter a name fo
 Page.UploadImage.Title=Upload Image - Sone
 Page.UploadImage.Error.InvalidImage=The image you were trying to upload could not be recognized. Please upload only JPEG (*.jpg or *.jpeg), or PNG (*.png) images.
 
-Page.EditImage.Title=Edit Image
+Page.EditImage.Title=Edit Image - Sone
 
-Page.DeleteImage.Title=Delete Image
+Page.DeleteImage.Title=Delete Image - Sone
 Page.DeleteImage.Page.Title=Delete Image
-Page.DeleteImage.Text.ImageWillBeGone=This will remove the image “{image}” from your album “{album}”. If it has already been inserted into Freenet it can not be removed from there forcefully. Do you want to do delete the image?
+Page.DeleteImage.Text.ImageWillBeGone=This will remove the image “{image}” from your album “{album}”. If it has already been inserted into Freenet it can not be removed from there forcefully. Do you want to delete the image?
 Page.DeleteImage.Button.Yes=Yes, delete image.
 Page.DeleteImage.Button.No=No, don’t delete image.
 
-Page.EditAlbum.Title=Edit Album
+Page.EditAlbum.Title=Edit Album - Sone
 
-Page.DeleteAlbum.Title=Delete Album
+Page.DeleteAlbum.Title=Delete Album - Sone
 Page.DeleteAlbum.Page.Title=Delete Album
 Page.DeleteAlbum.Text.AlbumWillBeGone=This will remove your album “{title}”. Do you really want to do that?
 Page.DeleteAlbum.Button.Yes=Yes, delete album.
@@ -279,7 +285,7 @@ Page.Search.Text.SoneHits=The following Sones match your search terms.
 Page.Search.Text.PostHits=The following posts match your search terms.
 Page.Search.Text.NoHits=No Sones or posts matched your search terms.
 
-Page.Rescue.Title=Rescue Sone
+Page.Rescue.Title=Rescue Sone - Sone
 Page.Rescue.Page.Title=Rescue Sone “{0}”
 Page.Rescue.Text.Description=The Rescue Mode lets you restore previous versions of your Sone. This can be necessary if your configuration was lost.
 Page.Rescue.Text.Procedure=The Rescue Mode works by fetching the latest inserted edition of your Sone. If an edition was successfully fetched it will be loaded into your Sone, letting you control your posts, profile, and other settings (you could do that in a second browser tab or window). If the fetched edition is not the one you want to restore, instruct the Rescue Mode to fetch the next older edition below.
@@ -301,7 +307,7 @@ Page.WotPluginMissing.Text.LoadPlugin=Please load the Web of Trust plugin in the
 
 Page.Logout.Title=Logout - Sone
 
-Page.Invalid.Title=Invalid Action Performed
+Page.Invalid.Title=Invalid Action Performed - Sone
 Page.Invalid.Page.Title=Invalid Action Performed
 Page.Invalid.Text=An invalid action was performed, or the action was valid but the parameters were not. Please go back to the {link}index page{/link} and try again. If the error persists you have probably found a bug.
 
@@ -407,6 +413,7 @@ WebInterface.DefaultText.Option.PostCutOffLength=Number of characters for the sn
 WebInterface.DefaultText.Option.PositiveTrust=The positive trust to assign
 WebInterface.DefaultText.Option.NegativeTrust=The negative trust to assign
 WebInterface.DefaultText.Option.TrustComment=The comment to set in the web of trust
+WebInterface.Button.Comment=Comment
 WebInterface.Confirmation.DeletePostButton=Yes, delete!
 WebInterface.Confirmation.DeleteReplyButton=Yes, delete!
 WebInterface.SelectBox.Choose=Choose…
diff --git a/src/main/resources/i18n/sone.fr.properties b/src/main/resources/i18n/sone.fr.properties
new file mode 100644 (file)
index 0000000..269a043
--- /dev/null
@@ -0,0 +1,450 @@
+Navigation.Menu.Sone.Name=Sone
+Navigation.Menu.Sone.Tooltip=Plugin du réseau social de Freenet
+Navigation.Menu.Sone.Item.Login.Name=Connexion
+Navigation.Menu.Sone.Item.Login.Tooltip=Se connecter à son Sone
+Navigation.Menu.Sone.Item.Index.Name=Votre Sone
+Navigation.Menu.Sone.Item.Index.Tooltip=Afficher votre Sone
+Navigation.Menu.Sone.Item.New.Name=New Posts and Replies
+Navigation.Menu.Sone.Item.New.Tooltip=Shows new posts and replies
+Navigation.Menu.Sone.Item.CreateSone.Name=Créer Sone
+Navigation.Menu.Sone.Item.CreateSone.Tooltip=Créer un nouveau Sone
+Navigation.Menu.Sone.Item.KnownSones.Name=Sones connus
+Navigation.Menu.Sone.Item.KnownSones.Tooltip=Montre tous les Sones connus
+Navigation.Menu.Sone.Item.Bookmarks.Name=Marque-pages
+Navigation.Menu.Sone.Item.Bookmarks.Tooltip=Affiche les messages dans les marque-pages
+Navigation.Menu.Sone.Item.EditProfile.Name=Editer le profil
+Navigation.Menu.Sone.Item.EditProfile.Tooltip=Editer le profil de votre Sone
+Navigation.Menu.Sone.Item.ImageBrowser.Name=Images
+Navigation.Menu.Sone.Item.ImageBrowser.Tooltip=Manages your Images
+Navigation.Menu.Sone.Item.DeleteSone.Name=Efface Sone
+Navigation.Menu.Sone.Item.DeleteSone.Tooltip=Efface les Sones actuels
+Navigation.Menu.Sone.Item.Logout.Name=Déconnexion
+Navigation.Menu.Sone.Item.Logout.Tooltip=Vous déconnecte de votre Sone actuel
+Navigation.Menu.Sone.Item.Options.Name=Options
+Navigation.Menu.Sone.Item.Options.Tooltip=Options concernant le plugin Sone
+Navigation.Menu.Sone.Item.Rescue.Name=Rescue
+Navigation.Menu.Sone.Item.Rescue.Tooltip=Rescue Sone
+Navigation.Menu.Sone.Item.About.Name=A propos
+Navigation.Menu.Sone.Item.About.Tooltip=Informations à propos de Sone
+
+Page.About.Title=A propos de - Sone
+Page.About.Page.Title=A propos
+Page.About.Flattr.Description=Si vous aimez Sone et aue vous voulez me récompenser, vous pouvez utiliser le bouton Flattr au bas de la page de recherche. Flattr est un système de micro-payement non anonyme comparable au principe du pouboire via internet où le montant que chaque utilisateur dépense est limité (le minimum est de 2€ par mois). Plus d'informations sur {link}flattr.com{/link}.
+Page.About.Homepage.Title=Paage d'accueil
+Page.About.Homepage.Description=Vous pouvez trouver plus d'informations ainsi que le code source de Sone sur la {link}page d'accueil{/link}.
+Page.About.License.Title=Licence
+
+Page.Options.Title=Options - Sone
+Page.Options.Page.Title=Options
+Page.Options.Page.Description=Ces options influencent le comportement de l'exécution du plugin Sone
+Page.Options.Section.SoneSpecificOptions.Title=Options spécifiques à Sone
+Page.Options.Section.SoneSpecificOptions.NotLoggedIn=Ces options sont uniquement disponibles si vous êtes {link}connecté{/link}.
+Page.Options.Section.SoneSpecificOptions.LoggedIn=Ces options sont uniquement disponibles pour le Sone entant que tel vous êtes enregistré.
+Page.Options.Option.AutoFollow.Description=si un nouveau  Sone est découvert, automatiquement le suivre.  Veuillez noter que cela suivra uniquement les Sones qui seront découverts après que cette option soit activée!
+Page.Options.Option.EnableSoneInsertNotifications.Description=If enabled, this will display notifications every time your Sone is being inserted or finishes inserting.
+Page.Options.Option.ShowNotificationNewSones.Description=Show notifications for new Sones.
+Page.Options.Option.ShowNotificationNewPosts.Description=Show notifications for new posts.
+Page.Options.Option.ShowNotificationNewReplies.Description=Show notifications for new replies.
+Page.Options.Section.AvatarOptions.Title=Avatar Options
+Page.Options.Option.ShowAvatars.Description=You can disable custom avatars here, depending on the selected criteria. If an avatar is disabled for a Sone, the automatically generated avatar is shown instead.
+Page.Options.Option.ShowAvatars.Never.Description=Never show custom avatars.
+Page.Options.Option.ShowAvatars.Followed.Description=Only show avatars for Sones that you follow.
+Page.Options.Option.ShowAvatars.ManuallyTrusted.Description=Only show avatars for Sones that you have manually assigned a trust value larger than 0 to.
+Page.Options.Option.ShowAvatars.Trusted.Description=Only show avatars for Sones that have a trust value larger than 0.
+Page.Options.Option.ShowAvatars.Always.Description=Always show custom avatars. Be warned: some avatars might contain disturbing or offensive imagery.
+Page.Options.Section.RuntimeOptions.Title=Comportement runtime
+Page.Options.Option.InsertionDelay.Description=Le nombre de secondes que l'inserteur de Sone attends après une modification d'un Sone avant qu'elle soit insérée.
+Page.Options.Option.PostsPerPage.Description=Le nombre de message à afficher par page avant que les boutons de contrôle de page sont affichés.
+Page.Options.Option.CharactersPerPost.Description=The number of characters to display from a post before cutting it off and showing a link to expand it (-1 to disable). The actual length of the snippet is determined by the option below.
+Page.Options.Option.PostCutOffLength.Description=The number of characters that are displayed if a post is deemed to long (see option above).
+Page.Options.Option.RequireFullAccess.Description=Que ce soit pour refuser l'accès à Sone à tout hôte à qui un accès complet n'a pas été accordé.
+Page.Options.Section.TrustOptions.Title=Réglages de confiance
+Page.Options.Option.PositiveTrust.Description=La quantité de note de confiance positive que vous voulez assigner à d'autres Sones en cochant la case en dessous d'un message ou d'une réponse.
+Page.Options.Option.NegativeTrust.Description=La quantité de note de confiance que vous voulez assigner à d'autres Sones en cliquand le X rouge en dessous d'un message ou d'une réponse. Cette valeur devrait être négative.
+Page.Options.Option.TrustComment.Description=Le commentaire qui sera mis dans le web of trust pour chaque note de confiance que vous assignez de Sone.
+Page.Options.Section.FcpOptions.Title=Réglages de l'Interface FCP
+Page.Options.Option.FcpInterfaceActive.Description=Activer l'interface FCP aafin de permettre à d'autres plugins et clients à distance d'accéder votre plugin Sone.
+Page.Options.Option.FcpFullAccessRequired.Description=Requière une connexion  FCP d'hôtes autorisés (Veuillez voir votre {link}configuration du noeud, section “FCP”{/link})
+Page.Options.Option.FcpFullAccessRequired.Value.No=Non
+Page.Options.Option.FcpFullAccessRequired.Value.Writing=Pour accès à l'écriture
+Page.Options.Option.FcpFullAccessRequired.Value.Always=toujours
+Page.Options.Section.Cleaning.Title=Nettoyer
+Page.Options.Option.ClearOnNextRestart.Description=Réinitialiser la configuration du plugin Sone au prochain redémarrage. Attention! {strong}Cela détruira tous vos Sones{/strong}. Soyez sûr d'avoir sauvegardé tout ce dont vous avez besoin! Vous devez également choisir "vrai" à l'option suivante pour procéder à la réinitialisation.
+Page.Options.Option.ReallyClearOnNextRestart.Description=Choisir "oui" pour cette option si vous voulez vraiment{strong}vraiment{/strong} effacer la configuration au prochain redémarrage.
+Page.Options.Warnings.ValueNotChanged=Cette option n'a pas été modifiée car la valeur que vous avez spécifiée n'est pas valide.
+Page.Options.Button.Save=Enregistrer
+
+Page.Login.Title=Connexion - Sone
+Page.Login.Page.Title=Connexion
+Page.Login.Label.SelectSone=Sélectionner Sone:
+Page.Login.Option.NoSone=Sélectionner Sone...
+
+Page.Login.CreateSone.Title=Créer Sone
+
+Page.CreateSone.Title=Créer un Sone - Sone
+
+Page.DeleteSone.Title=Effacer Sone - Sone
+Page.DeleteSone.Page.Title=Effacer Sone “{sone}”?
+Page.DeleteSone.Page.Description=Ceci n'effacera pas le Sone de Freenet(car ceci est impossible), celaa déconnectera seulement votre identité Web of Trust de Sone.
+Page.DeleteSone.Button.Yes=Oui, effacer.
+Page.DeleteSone.Button.No=Non, ne pas effacer.
+
+Page.Index.Title=Votre Sone - Sone
+Page.Index.Label.Text=Texte du message:
+Page.Index.Label.Sender=Expéditeur:
+Page.Index.Button.Post=Envoyer!
+Page.Index.PostList.Title=Envoyer du contenu
+Page.Index.PostList.Text.NoPostYet=Personne n'a encore écrit de message. vous devriez probablement commencer maintenant!
+
+Page.New.Title=New Posts and Replies - Sone
+Page.New.Page.Title=New Posts and Replies
+Page.New.NothingNew=At the moment there’s nothing new.
+
+Page.KnownSones.Title=Sones connus - Sone
+Page.KnownSones.Page.Title=Sones connus
+Page.KnownSones.Text.NoKnownSones=Il n'y a pour le moment aucun Sone connu.
+Page.KnownSones.Label.Sort=Sort:
+Page.KnownSones.Label.FilterSones=Filter Sones:
+Page.KnownSones.Sort.Field.Name=Name
+Page.KnownSones.Sort.Field.LastActivity=Last activity
+Page.KnownSones.Sort.Field.Posts=Number of posts
+Page.KnownSones.Sort.Field.Images=Number of images
+Page.KnownSones.Sort.Order.Ascending=Ascending
+Page.KnownSones.Sort.Order.Descending=Descending
+Page.KnownSones.Filter.Followed=Show only followed Sones
+Page.KnownSones.Filter.NotFollowed=Hide followed Sones
+Page.KnownSones.Filter.New=Show only new Sones
+Page.KnownSones.Filter.NotNew=Hide new Sones
+Page.KnownSones.Button.Apply=Apply
+Page.KnownSones.Button.FollowAllSones=Follow all Sones on this page
+Page.KnownSones.Button.UnfollowAllSones=Unfollow all Sones on this page
+
+Page.EditProfile.Title=Editer le profil - Sone
+Page.EditProfile.Page.Title=Éditer le profil
+Page.EditProfile.Page.Description=Sur cette page, vous pouvez entrer les données de votre profil.
+Page.EditProfile.Page.Hint.Optionality=Veuillez noter que chaque champ de ce profil est optionnel! Vous n'êtes pas obligés de remplir quoi que ce soit ici! Tout ce que vous remplissez ici serq probqblement stocké dans Freenet pour très longtemps!
+Page.EditProfile.Label.FirstName=Prénom:
+Page.EditProfile.Label.MiddleName=Prénom(s):
+Page.EditProfile.Label.LastName=Nom de famille:
+Page.EditProfile.Birthday.Title=Anniversaire
+Page.EditProfile.Birthday.Label.Day=Jour:
+Page.EditProfile.Birthday.Label.Month=Mois:
+Page.EditProfile.Birthday.Label.Year=Année:
+Page.EditProfile.Avatar.Title=Avatar
+Page.EditProfile.Avatar.Description=You can select one of your uploaded images to be shown as avatar. It should not be larger than 64×64 pixels because that is the largest size shown for other people (80×80 pixels is used for the page header).
+Page.EditProfile.Avatar.Delete=No avatar
+Page.EditProfile.Fields.Title=Champs personnalisés
+Page.EditProfile.Fields.Description=Vous pouvez ajouter ici des champs personalisés à votre profil. Ces champs peuvent contenir tout ce que vous voulez et être aussi laconique ou aussi long que vous le souhaitez. Veuillez juste vous souvenir que quand on parle d'anonymat, parfois le moins, le mieux.
+Page.EditProfile.Fields.Button.Edit=Éditer
+Page.EditProfile.Fields.Button.MoveUp=Déplacer vers le haut
+Page.EditProfile.Fields.Button.MoveDown=Déplacer vers le bas
+Page.EditProfile.Fields.Button.Delete=Effacer
+Page.EditProfile.Fields.Button.ReallyDelete=Vraiment effacer
+Page.EditProfile.Fields.AddField.Title=Ajouter un champ
+Page.EditProfile.Fields.AddField.Label.Name=Nom:
+Page.EditProfile.Fields.AddField.Button.AddField=Ajouter un champ
+Page.EditProfile.Button.Save=Enregistrer le Profil
+Page.EditProfile.Error.DuplicateFieldName=Le champ nom “{fieldName}” existe déjà.
+
+Page.EditProfileField.Title=Editer le champ de profil - Sone
+Page.EditProfileField.Page.Title=Editer le champ de profil
+Page.EditProfileField.Text=Entrez un nouveau nom pour ce champ de profil.
+Page.EditProfileField.Error.DuplicateFieldName=Le nom du champ que vous avez entré existe déjà.
+Page.EditProfileField.Button.Save=changer
+Page.EditProfileField.Button.Reset=Revenir à l'ancien nom
+Page.EditProfileField.Button.Cancel=ne pas changer le nom
+
+Page.DeleteProfileField.Title=Effacer le champ du profile - Sone
+Page.DeleteProfileField.Page.Title=Effacer le champs du profile
+Page.DeleteProfileField.Text=Voulez-vous vraiment effacer ce champ du profile ?
+Page.DeleteProfileField.Button.Yes=Oui, effacer
+Page.DeleteProfileField.Button.No=Non, ne pas effacer
+
+Page.CreatePost.Title=Créer message - Sone
+Page.CreatePost.Page.Title=Créer message
+Page.CreatePost.Label.Text=Poster du texte:
+Page.CreatePost.Button.Post=Envoyer !
+Page.CreatePost.Error.EmptyText=Vous n'avez entré aucun texte, ce qui est dommage. vous devriez essayer d'écrire plus !
+
+Page.CreateReply.Title=Créer une réponse - Sone
+Page.CreateReply.Page.Title=Créer une réponse
+Page.CreateReply.Error.EmptyText=Vous n'avez entré aucun texte, ce qui est dommage. Vous devriez essayer d'écrire plus !
+Page.CreateReply.Label.Text=Texte de réponse:
+Page.CreateReply.Button.Post=envoyer une réponse!
+
+Page.ViewSone.Title=Voir Sone - Sone
+Page.ViewSone.Page.TitleWithoutSone=Voir les Sones inconnus
+Page.ViewSone.NoSone.Description=Il n'y a pour le moment aucun Sone avec l'identité {sone}. Si vous cherchiez une identité sone spécifique, veuillez être sûr que cela soit visible dans votre web of trust!
+Page.ViewSone.UnknownSone.Description=Ce Sone n'a pas encore été récupéré. Veuillez revérifier un peu plus tard.
+Page.ViewSone.UnknownSone.LinkToWebOfTrust=Even though the Sone is still unknown, its Web of Trust profile might already be available:
+Page.ViewSone.WriteAMessage=Vous pouvez écrire un message à ce Sone ici. Veuillez noter que tout le monde sera capable de lire ce message!
+Page.ViewSone.PostList.Title=Messages par {sone}
+Page.ViewSone.PostList.Text.NoPostYet=Ce sone n'as encore rien envoyé.
+Page.ViewSone.Profile.Title=Profil
+Page.ViewSone.Profile.Label.Name=Nom
+Page.ViewSone.Profile.Label.Albums=Albums
+Page.ViewSone.Profile.Albums.Text.All=All albums
+Page.ViewSone.Profile.Name.WoTLink=Profil Web of trust
+Page.ViewSone.Replies.Title=Messages {sone} a répondu à
+
+Page.ViewPost.Title=Voir message - Sone
+Page.ViewPost.Page.Title=Voir les message par {sone}
+Page.ViewPost.Page.TitleUnknownSone=Voir le message inconnu
+Page.ViewPost.Text.UnknownPost=Ce message n'est peut être pas encore téléchargé.
+
+Page.Like.Title=Aime ce message - Sone
+Page.Unlike.Title=N'aime pas ce message - Sone
+
+Page.DeletePost.Title=Supprimer ce Sone - Sone
+Page.DeletePost.Page.Title=Effacer Sone
+Page.DeletePost.Text.PostWillBeGone=Supprimer un message le retirera de votre Sone. Cela ne le retirera pas de Freenet car cela n'est pas possible. Les versions plus anciennes de votre Sone contiendront toujours les messages effacés.
+Page.DeletePost.Button.Yes=Oui, effacer.
+Page.DeletePost.Button.No=Non, ne pas effacer.
+
+Page.DeleteReply.Title=Effacer la réponse - Sone
+Page.DeleteReply.Page.Title=Effacer la réponse
+Page.DeleteReply.Text.PostWillBeGone=Effacer une réponse la retirera de votre Sone. Cela ne la retirera pas de Freenet car cela n'est pas possible. Les versions plus anciennes de votre Sone contiendront toujours les réponses effacées.
+Page.DeleteReply.Button.Yes=Oui, effacer.
+Page.DeleteReply.Button.No=Non, ne pas effacer.
+
+Page.LockSone.Title=Verrouiller Sone - Sone
+
+Page.UnlockSone.Title=Déverouiller Sone - Sone
+
+Page.FollowSone.Title=Suivre Sone - Sone
+
+Page.UnfollowSone.Title=Ne plus suivre Sone - Sone
+
+Page.ImageBrowser.Title=Image Browser - Sone
+Page.ImageBrowser.Album.Title=Album “{album}”
+Page.ImageBrowser.Album.Error.NotFound.Text=The requested album could not be found. It is possible that it has not yet been downloaded, or that it has been deleted.
+Page.ImageBrowser.Sone.Title=Albums of {sone}
+Page.ImageBrowser.Sone.Error.NotFound.Text=The requested Sone could not be found. It is possible that it has not yet been downloaded.
+Page.ImageBrowser.Header.Albums=Albums
+Page.ImageBrowser.Header.Images=Images
+Page.ImageBrowser.Link.All=All Sones
+Page.ImageBrowser.CreateAlbum.Button.CreateAlbum=Create Album
+Page.ImageBrowser.Album.Edit.Title=Edit Album
+Page.ImageBrowser.Album.Delete.Title=Delete Album
+Page.ImageBrowser.Album.Label.AlbumImage=Album Image:
+Page.ImageBrowser.Album.Label.Title=Title:
+Page.ImageBrowser.Album.Label.Description=Description:
+Page.ImageBrowser.Album.AlbumImage.Choose=Choose Album Image…
+Page.ImageBrowser.Album.Button.Save=Save Album
+Page.ImageBrowser.Album.Button.Delete=Delete Album
+Page.ImageBrowser.Image.Edit.Title=Edit Image
+Page.ImageBrowser.Image.Title.Label=Title:
+Page.ImageBrowser.Image.Description.Label=Description:
+Page.ImageBrowser.Image.Button.MoveLeft=◀
+Page.ImageBrowser.Image.Button.Save=Save Image
+Page.ImageBrowser.Image.Button.MoveRight=►
+Page.ImageBrowser.Image.Delete.Title=Delete Image
+Page.ImageBrowser.Image.Button.Delete=Delete Image
+
+Page.CreateAlbum.Title=Create Album - Sone
+Page.CreateAlbum.Page.Title=Create Album
+Page.CreateAlbum.Error.NameMissing=You seem to have forgotten to enter a name for your new album.
+
+Page.UploadImage.Title=Upload Image - Sone
+Page.UploadImage.Error.InvalidImage=The image you were trying to upload could not be recognized. Please upload only JPEG (*.jpg or *.jpeg), or PNG (*.png) images.
+
+Page.EditImage.Title=Edit Image - Sone
+
+Page.DeleteImage.Title=Delete Image - Sone
+Page.DeleteImage.Page.Title=Delete Image
+Page.DeleteImage.Text.ImageWillBeGone=This will remove the image “{image}” from your album “{album}”. If it has already been inserted into Freenet it can not be removed from there forcefully. Do you want to delete the image?
+Page.DeleteImage.Button.Yes=Yes, delete image.
+Page.DeleteImage.Button.No=No, don’t delete image.
+
+Page.EditAlbum.Title=Edit Album - Sone
+
+Page.DeleteAlbum.Title=Delete Album - Sone
+Page.DeleteAlbum.Page.Title=Delete Album
+Page.DeleteAlbum.Text.AlbumWillBeGone=This will remove your album “{title}”. Do you really want to do that?
+Page.DeleteAlbum.Button.Yes=Yes, delete album.
+Page.DeleteAlbum.Button.No=No, don’t delete album.
+
+Page.Trust.Title=Faire confiance à Sone - Sone
+
+Page.Distrust.Title=Se méfier de ce Sone - Sone
+
+Page.Untrust.Title=Ne plus faire confiance en ce Sone - Sone
+
+Page.MarkAsKnown.Title=Marquer comme connu - Sone
+
+Page.Bookmark.Title=Marque-page - Sone
+Page.Unbookmark.Title=Effacer le marque-page - Sone
+Page.Bookmarks.Title=MArque-pages - Sone
+Page.Bookmarks.Page.Title=Marque-pages
+Page.Bookmarks.Text.NoBookmarks=Vous n'avez aucun marque-page défini pour le moment. Vous pouvez ajouter des messages à vos marque-pages en cliquant sur l'étoile en dessous du message.
+Page.Bookmarks.Text.PostsNotLoaded=Certains de vos messages dans vos marque-pages ne sont pas affichés car ils n'ont pas pu être chargés. Ceci peut arriver si vous avez redémarré Sone récemment ou si le Sone original a effacé le message. Si vous êtes suffisamment sûr aue ces messages n'existent plus, vous pouvez les {link}retirer de vos marque pages{/link}.
+
+Page.Search.Title=Recherche - Sone
+Page.Search.Page.Title=Résultats de recherche
+Page.Search.Text.SoneHits=Les Sones suivants correspondent aux termes de votre recherche.
+Page.Search.Text.PostHits=Les messages suivants correspondent aux termes de votre recherche.
+Page.Search.Text.NoHits=Aucun Sone ou message ne correspond aux termes de votre recherche.
+
+Page.Rescue.Title=Rescue Sone - Sone
+Page.Rescue.Page.Title=Rescue Sone “{0}”
+Page.Rescue.Text.Description=The Rescue Mode lets you restore previous versions of your Sone. This can be necessary if your configuration was lost.
+Page.Rescue.Text.Procedure=The Rescue Mode works by fetching the latest inserted edition of your Sone. If an edition was successfully fetched it will be loaded into your Sone, letting you control your posts, profile, and other settings (you could do that in a second browser tab or window). If the fetched edition is not the one you want to restore, instruct the Rescue Mode to fetch the next older edition below.
+Page.Rescue.Text.Fetching=The Sone Rescuer is currently fetching edition {0} of your Sone.
+Page.Rescue.Text.Fetched=The Sone Rescuer has downloaded edition {0} of your Sone. Please check your posts, replies, and profile. If you like what the current Sone contains, just unlock it.
+Page.Rescue.Text.FetchedLast=The Sone rescuer has downloaded the last available edition. If it did not manage to restore your Sone you are probably out of luck now.
+Page.Rescue.Text.NotFetched=The Sone Rescuer could not download edition {0} of your Sone. Please either try again with edition {0}, or try the next older edition.
+Page.Rescue.Label.NextEdition=Next edition:
+Page.Rescue.Button.Fetch=Fetch edition
+
+Page.NoPermission.Title=Accès non autorisé - Sone
+Page.NoPermission.Page.Title=Accès non autorisé
+Page.NoPermission.Text.NoPermission=Vous avez tenté une action pour laquelle vous n'avez pas les droits suffisants. Veuillez vous abstenir de ces actions dans le futur ou nous serons forcés de prendre des contre-mesures!
+
+Page.DismissNotification.Title=Effacer la notification - Sone
+
+Page.WotPluginMissing.Text.LoadPlugin=Veuillez charger le plugin Web of Trust dans le {link}plugin manager{/link}.
+Page.WotPluginMissing.Text.WotRequired=Parce que le Web of Trust est une partie intégrante de Sone, le plugin Web of trust doit être chargé afin de pouvoir faire fontionner Sone.
+
+Page.Logout.Title=Déconnexion - Sone
+
+Page.Invalid.Title=Action invalide réalisée - Sone
+Page.Invalid.Page.Title=Action invalide réalisée
+Page.Invalid.Text=Une action invalide a été effectuée, ou l'action était valide mes les paramètres ne l'étaient pas. Veuillez retourner à la {link}page d'index{/link} et veuillez réessayer. Si l'erreur persiste, vous avez probablement trouvé un bug.
+
+View.Search.Button.Search=Recherche
+
+View.CreateSone.Text.WotIdentityRequired=Pour créer un Sone vous avez besoin d'une identité venant du {link}plugin Web of Trust {/link}.
+View.CreateSone.Select.Default=Sélectionner une identité
+View.CreateSone.Text.NoIdentities=Vous n'avez pas d'identité "Web of Trust". Veuillez vous  diriger sur la page du  {link}plugin Web of Trust {/link} et créer une identité.
+View.CreateSone.Text.NoNonSoneIdentities=Vous n'avez aucune identité "Web of Trust" qui ne sont pas déjà un Sone. Utilisez une des identités "Web of Trust" restantes pour créer un nouveau Sone ou dirigez vous sur la page du {link} plugin "Web of Trust"{/link} pour créer une nouvelle identité.
+View.CreateSone.Button.Create=Créer un Sone
+View.CreateSone.Text.Error.NoIdentity=Vous n'avez pas sélectionné d'identité.
+
+View.Sone.Label.LastUpdate=Dernière mise à jour:
+View.Sone.Text.UnknownDate=Inconnu
+View.Sone.Stats.Posts={0,number} {0,choice,0#posts|1#post|1<posts}
+View.Sone.Stats.Replies={0,number} {0,choice,0#replies|1#reply|1<replies}
+View.Sone.Stats.Images={0,number} {0,choice,0#images|1#image|1<images}
+View.Sone.Button.UnlockSone=Déverrouiller
+View.Sone.Button.UnlockSone.Tooltip=Permettre à ce Sone d'être inséré maintenant
+View.Sone.Button.LockSone=verrouiller
+View.Sone.Button.LockSone.Tooltip=Empêcher ce Sone d'être inséré maintenant
+View.Sone.Button.UnfollowSone=ne plus suivre
+View.Sone.Button.FollowSone=suivre
+View.Sone.Status.Modified=Ce Sone a été modifié et attends d'être inséré.
+View.Sone.Status.Unknown=Ce Sone n'a pas encore été récupéré.
+View.Sone.Status.Idle=Ce Sone est inactif, c'est à dire qu'il n'est pas en train d'être inséré ou téléchargé.
+View.Sone.Status.Downloading=Ce sone est en train d'être téléchargé.
+View.Sone.Status.Inserting=Ce sone est en train d'être inséré.
+
+View.SoneMenu.Link.AllAlbums=all albums
+
+View.Post.UnknownAuthor=(inconnu)
+View.Post.WebOfTrustLink=web of trust profile
+View.Post.Permalink=lier le message
+View.Post.PermalinkAuthor=Lier l'auteur
+View.Post.Bookmarks.PostIsBookmarked=Ce message a été ajouté aux marque-pages, cliquer pour retirer des marque-pages
+View.Post.Bookmarks.PostIsNotBookmarked=Ce message n'est pas dans les marque-pages, cliquer pour marquer cette page
+View.Post.DeleteLink=Effacer
+View.Post.SendReply=Répondre!
+View.Post.Reply.DeleteLink=Effacer
+View.Post.LikeLink=Aime
+View.Post.UnlikeLink=N'aime pas
+View.Post.ShowSource=Toggle Parser
+View.Post.NotDownloaded=Ce message n'a pas encore été téléchargé, ou a été effacé.
+View.Post.ShowMore=show more
+View.Post.ShowLess=show less
+
+View.UpdateStatus.Text.ChooseSenderIdentity=Choisir l'identité de l'expéditeur
+
+View.Trust.Tooltip.Trust=Faire confiance à cette personne
+View.Trust.Tooltip.Distrust=Assigner une note négative en confiance à cette personne
+View.Trust.Tooltip.Untrust=Retirer votre note de confiance de cette personne
+
+View.CreateAlbum.Title=Create Album
+View.CreateAlbum.Label.Name=Name:
+View.CreateAlbum.Label.Description=Description:
+
+View.UploadImage.Title=Upload Image
+View.UploadImage.Label.Title=Title:
+View.UploadImage.Label.Description=Description:
+View.UploadImage.Button.UploadImage=Upload Image
+
+View.Time.InTheFuture=dans le futur
+View.Time.AFewSecondsAgo=au cours des dernières secondes passées
+View.Time.HalfAMinuteAgo=au cours des 30 dernières secondes
+View.Time.AMinuteAgo=au cours de la dernière minute
+View.Time.XMinutesAgo=${min} il y a quelques minutes
+View.Time.HalfAnHourAgo=au cours de la dernière demi heure
+View.Time.AnHourAgo=il y a environ une heure
+View.Time.XHoursAgo=${heure} au cours des dernières heures
+View.Time.ADayAgo=il y a environ un jour
+View.Time.XDaysAgo=${jour} il y a quelques jours
+View.Time.AWeekAgo=il y a environ une semaine
+View.Time.XWeeksAgo=${semaine} au cours des dernières semaines
+View.Time.AMonthAgo=au cours du dernier mois
+View.Time.XMonthsAgo=${mois} au cours des derniers mois
+View.Time.AYearAgo=au cours de la dernière année
+View.Time.XYearsAgo=${année} au cours des dernières années
+
+WebInterface.DefaultText.StatusUpdate=Exprimez-vous
+WebInterface.DefaultText.Message=Écrire un message...
+WebInterface.DefaultText.Reply=Écrire une réponse...
+WebInterface.DefaultText.FirstName=Prénom
+WebInterface.DefaultText.MiddleName=Prénom
+WebInterface.DefaultText.LastName=Nom de famille
+WebInterface.DefaultText.BirthDay=Jour
+WebInterface.DefaultText.BirthMonth=Mois
+WebInterface.DefaultText.BirthYear=Année
+WebInterface.DefaultText.FieldName=nom du champ
+WebInterface.DefaultText.Option.InsertionDelay=Temps d'attente après qu'un Sone aie été modifié avant l'insertion (en secondes)
+WebInterface.DefaultText.Search=Que recherchez vous ?
+WebInterface.DefaultText.CreateAlbum.Name=Album title
+WebInterface.DefaultText.CreateAlbum.Description=Album description
+WebInterface.DefaultText.EditAlbum.Title=Album title
+WebInterface.DefaultText.EditAlbum.Description=Album description
+WebInterface.DefaultText.UploadImage.Title=Image title
+WebInterface.DefaultText.UploadImage.Description=Image description
+WebInterface.DefaultText.EditImage.Title=Image title
+WebInterface.DefaultText.EditImage.Description=Image description
+WebInterface.DefaultText.Option.PostsPerPage=Nombre de messages à afficher par page
+WebInterface.DefaultText.Option.CharactersPerPost=Number of characters a post must have to be shortened
+WebInterface.DefaultText.Option.PostCutOffLength=Number of characters for the snippet of the shortened post
+WebInterface.DefaultText.Option.PositiveTrust=La note de confiance positive à assigner
+WebInterface.DefaultText.Option.NegativeTrust=Une note de confiance négative à assigner
+WebInterface.DefaultText.Option.TrustComment=Le commentaire à mettre dans le "Web of Trust"
+WebInterface.Button.Comment=Commenter
+WebInterface.Confirmation.DeletePostButton=Oui, effacer!
+WebInterface.Confirmation.DeleteReplyButton=Oui, effacer!
+WebInterface.SelectBox.Choose=Choisir...
+WebInterface.SelectBox.Yes=Oui
+WebInterface.SelectBox.No=Non
+WebInterface.ClickToShow.Replies=Cliquer ici pour afficher les réponses cachées.
+WebInterface.VersionInformation.CurrentVersion=Version actuelle:
+WebInterface.VersionInformation.LatestVersion=Dernière version:
+
+Notification.ClickHereToRead=Cliquer ici pour lire le texte entier de la notification.
+Notification.FirstStart.Text=Il semble que ce soit la première fois que vous démarrez Sone. Pour démarrer, créez un nouveau Sone depuis une identité Web of Trust et commencez à suivre d'autres Sones.
+Notification.Startup.Text=Sone est cours de démarrage. Cela peut prendre un certain temps afin de récupérer toutes les identités et Sones du Web of Trust. Si il vous manque certains éléments, veuillez être patient, ils réapparaîtrons probablement assez tôt.
+Notification.ConfigNotRead.Text=Le fichier de configuration “sone.properties” n'a pas pu être lu probablement car il n'a pas été sauvegardé correctement. Ceci peut arriver avec les versions antérieures à Sone 0.3.3 et il n'y a rien que vous puissiez faire à ce propos.
+Notification.Button.Dismiss=Rejeter
+Notification.NewSone.ShortText=De nouveaux Sones ont été découverts:
+Notification.NewSone.Text=De nouveaux Sones ont été découverts:
+Notification.NewPost.ShortText=De nouveaux messages ont été découverts.
+Notification.NewPost.Text=De nouveaux messages ont été découverts provenant des Sones suivants:
+Notification.NewPost.Button.MarkRead=Marquer comme lus
+Notification.NewReply.ShortText=De nouvelles réponses ont été découvertes.
+Notification.NewReply.Text=De nouvelles réponses ont été trouvées pour les messages des Sones suivants:
+Notification.SoneIsBeingRescued.Text=Les Sones suivants sont actuellement en cours de restauration.
+Notification.SoneRescued.Text=Les Sones suivants ont été sauvés:
+Notification.SoneRescued.Text.RememberToUnlock=Veuillez vous souvenir de contrôler les messages et réponses que vous avez donnés et n'oubliez ps de déverrouiller vos Sones!
+Notification.LockedSones.Text=Les Sones suivants ont été verrouillés pour plus de 5 minutes. Veuillez vérifier si vous voulez vraiment garder ces Sones bloqués:
+Notification.NewVersion.Text=La version {version} du pluggin Sone a été trouvée. Téléchargez la depuis USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}​!
+Notification.InsertingImages.Text=The following images are being inserted:
+Notification.InsertedImages.Text=The following images have been inserted:
+Notification.ImageInsertFailed.Text=The following images could not be inserted:
+Notification.Mention.ShortText=Vous avez été mentionné.
+Notification.Mention.Text=Vous avez été mentionné dans les messages suivants:
+Notification.SoneInsert.Duration={0,number} {0,choice,0#seconds|1#second|1<seconds}
+
+# Updated lines: 7-8, 17-18, 25-26, 44-54, 58-59, 99-101, 106-120, 133-135, 179, 185-186, 218-265, 288-297, 325-327, 340, 343, 355-356, 364-371, 402-409, 411-412, 442-444, 447
diff --git a/src/main/resources/i18n/sone.no.properties b/src/main/resources/i18n/sone.no.properties
new file mode 100644 (file)
index 0000000..a1868b8
--- /dev/null
@@ -0,0 +1,450 @@
+Navigation.Menu.Sone.Name=Sone
+Navigation.Menu.Sone.Tooltip=Freenet Sosiale Medier-Plugin
+Navigation.Menu.Sone.Item.Login.Name=Log på
+Navigation.Menu.Sone.Item.Login.Tooltip=Logg på din Sone
+Navigation.Menu.Sone.Item.Index.Name=Din Sone
+Navigation.Menu.Sone.Item.Index.Tooltip=Vis din Sone
+Navigation.Menu.Sone.Item.New.Name=Nye innlegg og svar
+Navigation.Menu.Sone.Item.New.Tooltip=Viser nye innlegg og svar
+Navigation.Menu.Sone.Item.CreateSone.Name=Lag Sone
+Navigation.Menu.Sone.Item.CreateSone.Tooltip=Lag en ny Sone
+Navigation.Menu.Sone.Item.KnownSones.Name=Kjente Soner
+Navigation.Menu.Sone.Item.KnownSones.Tooltip=Vis alle kjente Soner
+Navigation.Menu.Sone.Item.Bookmarks.Name=Bokmerker
+Navigation.Menu.Sone.Item.Bookmarks.Tooltip=Vis bokmerkede innlegg
+Navigation.Menu.Sone.Item.EditProfile.Name=Endre Profil
+Navigation.Menu.Sone.Item.EditProfile.Tooltip=Endre profilen til din Sone
+Navigation.Menu.Sone.Item.ImageBrowser.Name=Bilder
+Navigation.Menu.Sone.Item.ImageBrowser.Tooltip=Behandle dine bilder
+Navigation.Menu.Sone.Item.DeleteSone.Name=Slett Sonen
+Navigation.Menu.Sone.Item.DeleteSone.Tooltip=Sletter den gjeldende Sonen
+Navigation.Menu.Sone.Item.Logout.Name=Logg av
+Navigation.Menu.Sone.Item.Logout.Tooltip=Logger deg av den gjeldende Sonen
+Navigation.Menu.Sone.Item.Options.Name=Innstillinger
+Navigation.Menu.Sone.Item.Options.Tooltip=Innstillinger for Sone-pluginen
+Navigation.Menu.Sone.Item.Rescue.Name=Redder
+Navigation.Menu.Sone.Item.Rescue.Tooltip=Redd Sone
+Navigation.Menu.Sone.Item.About.Name=Om
+Navigation.Menu.Sone.Item.About.Tooltip=Informasjon om Sone
+
+Page.About.Title=Om - Sone
+Page.About.Page.Title=Om
+Page.About.Flattr.Description=Hvis du liker Sone og du ønsker å belønne meg, kan du bruke Flattr-knappen på bunn av siden. Flattr er en ikke-anonym mikro betaling som fungerer som et Internet tips-beger hvor beløpet brukeren donerer er begrenset (Laveste er 2 € per måned). Mer informasjon kan bli funnet hos {link}flattr.com{/link}.
+Page.About.Homepage.Title=Hjemmeside
+Page.About.Homepage.Description=Du kan finne mer informasjon om kildekoden til Sone på {link}hjemmesiden{/link}.
+Page.About.License.Title=Lisens
+
+Page.Options.Title=Innstillinger - Sone
+Page.Options.Page.Title=Innstillinger
+Page.Options.Page.Description=Disse innstillingene påvirker oppførselen til Sone-tillegget.
+Page.Options.Section.SoneSpecificOptions.Title=Sone-spesifikke innstillinger
+Page.Options.Section.SoneSpecificOptions.NotLoggedIn=Disse valgene er bare tilgjengelig hvis du er {link}logget inn{/link}.
+Page.Options.Section.SoneSpecificOptions.LoggedIn=Disse innstillingene er bare tilgjengelig når du er logget på og de er bare gyldig for den Sonen du er logget på som.
+Page.Options.Option.AutoFollow.Description=Hvis en ny Sone blir oppdaget, følg den automatisk. Legg merke til at dette vil bare følge Soner som blir oppdaget etter at dette valget ble aktivert!
+Page.Options.Option.EnableSoneInsertNotifications.Description=Hvis aktivert vil det varsles hver gang din Sone setter inn eller er ferdig å sette inn.
+Page.Options.Option.ShowNotificationNewSones.Description=Vis varsel for nye Soner.
+Page.Options.Option.ShowNotificationNewPosts.Description=Vis varsel for nye innlegg.
+Page.Options.Option.ShowNotificationNewReplies.Description=Vis varsel for nye svar.
+Page.Options.Section.AvatarOptions.Title=Avatarinnstillinger
+Page.Options.Option.ShowAvatars.Description=Du kan deaktivere egendefinerte avatarer her, avhengig av det valgte kriteriet. Hvis avatar er deaktivert for en Sone, blir det automatisk genererte avataret vist istedenfor.
+Page.Options.Option.ShowAvatars.Never.Description=Aldri vis egendefinerte avatarer.
+Page.Options.Option.ShowAvatars.Followed.Description=Bare vis avatar for Soner du følger.
+Page.Options.Option.ShowAvatars.ManuallyTrusted.Description=Bare vis avatar for Soner du manuelt har gitt en tillit større en 0.
+Page.Options.Option.ShowAvatars.Trusted.Description=Bare vis avatar for Soner som har en tillit større enn 0.
+Page.Options.Option.ShowAvatars.Always.Description=Alltid vis egendefinerte avatarer. Advarsel: Noen avatarer kan inneholde forstyrrende eller provoserende bilder.
+Page.Options.Section.RuntimeOptions.Title=Oppførsel ved kjøretid
+Page.Options.Option.InsertionDelay.Description=Antall sekunder Sone-innsetteren skal vente etter en endring av en Sone før den blir innsatt.
+Page.Options.Option.PostsPerPage.Description=Antallet innlegg å vise pr side før side-kontroller blir vist.
+Page.Options.Option.CharactersPerPost.Description=Antall tegn å vise fra et innlegg før resten blir skjult og en link blir vist for å utvide til hele innlegget (-1 for å deaktivere). Lengden på den viste teksten kan endres under.
+Page.Options.Option.PostCutOffLength.Description=Antallet tegn som blir vist hvis et innlegg er for langt (Se innstilling over).
+Page.Options.Option.RequireFullAccess.Description=For å avslå tilgang til Sone fra enhver host som ikke har blitt gitt full tilgang.
+Page.Options.Section.TrustOptions.Title=Tillitsinnstillinger
+Page.Options.Option.PositiveTrust.Description=Mengden positiv tillit du ønsker å gi en annen Sone ved å klikke på hake-merket under et innlegg eller ved å skrive et svar.
+Page.Options.Option.NegativeTrust.Description=Mengden tillit du vil gi til andre Soner ved å klikke på den røde X'en nedenfor et innlegg eller svar. Denne verdien burde være negativ.
+Page.Options.Option.TrustComment.Description=Kommentaren som vil bli satt i 'Web Of Trust' for all tillit gitt via Sone.
+Page.Options.Section.FcpOptions.Title=FCP-grensesnitts innstillinger
+Page.Options.Option.FcpInterfaceActive.Description=Aktiver FCP-grensesnittet for å tillate andre tillegg og andre klienter til å aksessere dit Sone-tillegg.
+Page.Options.Option.FcpFullAccessRequired.Description=Påkrev FCP tilkobling fra tillate hoster (se din {link}nodes konfigurasjon, seksjon «FCP»{/link})
+Page.Options.Option.FcpFullAccessRequired.Value.No=Nei
+Page.Options.Option.FcpFullAccessRequired.Value.Writing=For skrivetilgang
+Page.Options.Option.FcpFullAccessRequired.Value.Always=Alltid
+Page.Options.Section.Cleaning.Title=Rydd opp
+Page.Options.Option.ClearOnNextRestart.Description=Nullstill konfigurasjonen til Sone-tillegget ved neste omstart. Advarsel! {strong}Dette vil ødelegge alle dine Soner{/strong} så forsikre deg om at du har tatt backup av alt du fremdeles trenger! Du vil måtte sette det neste valget til 'true' for faktisk å nullstille.
+Page.Options.Option.ReallyClearOnNextRestart.Description=Denne innstillingen må bli satt til «ja» hvis du virkelig {strong}virkelig{/strong} ønsker å slette Sone-tilleggets innstillinger ved neste omstart.
+Page.Options.Warnings.ValueNotChanged=Denne innstillingen ble ikke endret fordi verdien du spesifiserte ikke var gyldig.
+Page.Options.Button.Save=Lagre
+
+Page.Login.Title=Logg på - Sone
+Page.Login.Page.Title=Logg på
+Page.Login.Label.SelectSone=Velg Sone:
+Page.Login.Option.NoSone=Velg Sone…
+
+Page.Login.CreateSone.Title=Lag Sone
+
+Page.CreateSone.Title=Lag sone - Sone
+
+Page.DeleteSone.Title=Slett Sonen - Sone
+Page.DeleteSone.Button.No=Nei, ikke slett.
+Page.DeleteSone.Button.Yes=Ja, slett.
+Page.DeleteSone.Page.Description=Dette vil ikke slette Sonen fra Freenet (Fordi det er umulig), det vil bare koble fra ditt 'Web Of Trust'-pseudonym fra Sone.
+Page.DeleteSone.Page.Title=Slette Sonen «{sone}»?
+
+Page.Index.Title=Din Sone - Sone
+Page.Index.Label.Text=Innleggstekst:
+Page.Index.Label.Sender=Avsender:
+Page.Index.Button.Post=Publiser!
+Page.Index.PostList.Title=Innleggsstrøm
+Page.Index.PostList.Text.NoPostYet=Ingen har skrevet noen innlegg enda. Du burde starte med en gang!
+
+Page.New.Title=Nye innlegg og svar - Sone
+Page.New.Page.Title=Nye innlegg og svar
+Page.New.NothingNew=For øyeblikket er det ingen ting nytt
+
+Page.KnownSones.Title=Kjente Soner - Sone
+Page.KnownSones.Page.Title=Kjente Soner
+Page.KnownSones.Text.NoKnownSones=Det er for øyeblikket ingen kjente Soner.
+Page.KnownSones.Label.Sort=Sorter:
+Page.KnownSones.Label.FilterSones=Filtrer Soner:
+Page.KnownSones.Sort.Field.Name=Navn
+Page.KnownSones.Sort.Field.LastActivity=Siste aktivitet
+Page.KnownSones.Sort.Field.Posts=Antall innlegg
+Page.KnownSones.Sort.Field.Images=Antall bilder
+Page.KnownSones.Sort.Order.Ascending=Stigende
+Page.KnownSones.Sort.Order.Descending=Avtagende
+Page.KnownSones.Filter.Followed=Vis bare soner som følges
+Page.KnownSones.Filter.NotFollowed=Gjem Soner som følges
+Page.KnownSones.Filter.New=Vis bare nye Soner
+Page.KnownSones.Filter.NotNew=Gjem nye Soner
+Page.KnownSones.Button.Apply=Tilføy
+Page.KnownSones.Button.FollowAllSones=Følg alle Soner på denne siden
+Page.KnownSones.Button.UnfollowAllSones=Slutt å følge alle Soner på denne siden
+
+Page.EditProfile.Title=Endre profil - Sone
+Page.EditProfile.Page.Title=Endre profil
+Page.EditProfile.Page.Description=På denne siden kan du skrive inn profil-data.
+Page.EditProfile.Page.Hint.Optionality=Husk, hver eneste felt på denne profilen er valgfritt! Ingen av de er påkrevd å fylle ut! I tillegg vil sannsynligvis alt du skriver her bli lagret i Freenet veldig lenge!
+Page.EditProfile.Label.FirstName=Fornavn:
+Page.EditProfile.Label.MiddleName=Mellomnavn:
+Page.EditProfile.Label.LastName=Etternavn:
+Page.EditProfile.Birthday.Title=Bursdag
+Page.EditProfile.Birthday.Label.Day=Dag:
+Page.EditProfile.Birthday.Label.Month=Måned:
+Page.EditProfile.Birthday.Label.Year=År:
+Page.EditProfile.Avatar.Title=Avatar
+Page.EditProfile.Avatar.Description=Du kan velge en av dine opplastede bilder til å bli vist som avatar. Det burde ikke være større enn 64×64 pixler fordi det er den største størrelse som blir vist for andre (80×80 pixler blir brukt for sidens overskrift).
+Page.EditProfile.Avatar.Delete=Ingen avatar
+Page.EditProfile.Fields.Title=Egendefinerte felt
+Page.EditProfile.Fields.Description=Her kan du skrive inn egendefinerte felt i din profil. Disse feltene kan inneholde hva som helst og kan være så konsis eller utfyllende som du vil. Bare husk at når det kommer til anonymitet så gjelder 'less is more'.
+Page.EditProfile.Fields.Button.Edit=endre
+Page.EditProfile.Fields.Button.MoveUp=flytt opp
+Page.EditProfile.Fields.Button.MoveDown=flytt ned
+Page.EditProfile.Fields.Button.Delete=slett
+Page.EditProfile.Fields.Button.ReallyDelete=virkelig slett
+Page.EditProfile.Fields.AddField.Title=Legg til felt
+Page.EditProfile.Fields.AddField.Label.Name=Navn:
+Page.EditProfile.Fields.AddField.Button.AddField=Legg til felt
+Page.EditProfile.Button.Save=Lagre profil
+Page.EditProfile.Error.DuplicateFieldName=Feltet «{fieldName}» eksisterer allerede.
+
+Page.EditProfileField.Title=Endre profil-felt - Sone
+Page.EditProfileField.Page.Title=Endre profil-felt
+Page.EditProfileField.Text=Skriv et nytt navn for dette profil-feltet.
+Page.EditProfileField.Error.DuplicateFieldName=Felt-navnet du skrev inn eksisterer allerede.
+Page.EditProfileField.Button.Save=Endre
+Page.EditProfileField.Button.Reset=Bytt tilbake til gammelt navn
+Page.EditProfileField.Button.Cancel=Ikke endre navn
+
+Page.DeleteProfileField.Title=Slett profil-felt - Sone
+Page.DeleteProfileField.Page.Title=Slett Profil-felt
+Page.DeleteProfileField.Text=Vil du virkelig slette dette profil-feltet?
+Page.DeleteProfileField.Button.Yes=Ja, slett
+Page.DeleteProfileField.Button.No=Nei, ikke slett
+
+Page.CreatePost.Title=Lag nytt innlegg - Sone
+Page.CreatePost.Page.Title=Lag nytt innlegg
+Page.CreatePost.Label.Text=Innleggstekst:
+Page.CreatePost.Button.Post=Publiser!
+Page.CreatePost.Error.EmptyText=Du skrev ingen test, noe som er litt synd. Du burde prøve å skrive mer!
+
+Page.CreateReply.Title=Lag nytt svar - Sone
+Page.CreateReply.Page.Title=Lag nytt svar
+Page.CreateReply.Error.EmptyText=Du skrev ikke inn noe tekst, noe som er synd. Du burde prøve å skrive mer!
+Page.CreateReply.Label.Text=Svartekst:
+Page.CreateReply.Button.Post=Publiser Svar!
+
+Page.ViewSone.Title=Vis sone - Sone
+Page.ViewSone.Page.TitleWithoutSone=Vis ukjent Sone
+Page.ViewSone.NoSone.Description=Det er foreløpig ingen kjente Soner med ID {sone}. Hvis du så etter en spesifikk Sone, forsikre deg om at den er synlig i din 'Web Of Trust'!
+Page.ViewSone.UnknownSone.Description=Denne Sonen har ikke blitt mottatt enda. Prøv igjen om en liten stund.
+Page.ViewSone.UnknownSone.LinkToWebOfTrust=Selv om Sonen fremdeles er ukjent, er kanskje 'web of trust'-profilen tilgjengelig:
+Page.ViewSone.WriteAMessage=Du kan skrive en melding til denne Sonen. Legg merke til at alle vil kunne lese denne meldingen!
+Page.ViewSone.PostList.Title=Innlegg av {sone}
+Page.ViewSone.PostList.Text.NoPostYet=Denne Sonen har ikke publisert noe enda.
+Page.ViewSone.Profile.Title=Profil
+Page.ViewSone.Profile.Label.Name=Navn
+Page.ViewSone.Profile.Label.Albums=Albumer
+Page.ViewSone.Profile.Albums.Text.All=Alle album
+Page.ViewSone.Profile.Name.WoTLink='Web Of Trust'-profil
+Page.ViewSone.Replies.Title=Innlegg {sone} har svart på
+
+Page.ViewPost.Title=Vis innlegg - Sone
+Page.ViewPost.Page.Title=Vis innlegg av {sone}
+Page.ViewPost.Page.TitleUnknownSone=Vis ukjent innlegg
+Page.ViewPost.Text.UnknownPost=Dette innlegget har ikke blitt lastet ned.
+
+Page.Like.Title=Lik innlegg - Sone
+Page.Unlike.Title=Fjern liker på innlegg - Sone
+
+Page.DeletePost.Title=Slett Sonen - Sone
+Page.DeletePost.Page.Title=Slett sone
+Page.DeletePost.Text.PostWillBeGone=Sletting av innlegg vil fjerne den fra din Sone. Det vil ikke bli slettet fra Freenet fordi det er umulig. Eldre utgaver av din Sone vil alltid inkludere det slettede innlegget.
+Page.DeletePost.Button.Yes=Ja, slett.
+Page.DeletePost.Button.No=Nei, ikke slett.
+
+Page.DeleteReply.Title=Slett svar - Sone
+Page.DeleteReply.Page.Title=Slett svar
+Page.DeleteReply.Text.PostWillBeGone=Sletting av et svar vil fjerne det fra din Sone. Det vil ikke fjerne det fra Freenet fordi det er umulig. Endre utgaver av din Sone vil alltid inkludere det slettede svaret.
+Page.DeleteReply.Button.Yes=Ja, slett.
+Page.DeleteReply.Button.No=Nei, ikke slett.
+
+Page.LockSone.Title=Lås Sone - Sone
+
+Page.UnlockSone.Title=Lås opp Sonen - Sone
+
+Page.FollowSone.Title=Følg Sone - Sone
+
+Page.UnfollowSone.Title=Ikke følg Sonen - Sone
+
+Page.ImageBrowser.Title=Bildeviser - Sone
+Page.ImageBrowser.Album.Title=Album «{album}»
+Page.ImageBrowser.Album.Error.NotFound.Text=Det forespurte albumet kunne ikke bli funnet. Det er mulig det ikke har blitt lastet ned eller at det er slettet.
+Page.ImageBrowser.Sone.Title=Album til {sone}
+Page.ImageBrowser.Sone.Error.NotFound.Text=Den forespurte Sonen kunne ikke bli funnet. Det er mulig at den ikke er lastet ned enda.
+Page.ImageBrowser.Header.Albums=Album
+Page.ImageBrowser.Header.Images=Bilder
+Page.ImageBrowser.Link.All=Alle Soner
+Page.ImageBrowser.CreateAlbum.Button.CreateAlbum=Lag album
+Page.ImageBrowser.Album.Edit.Title=Endre album
+Page.ImageBrowser.Album.Delete.Title=Slett album
+Page.ImageBrowser.Album.Label.AlbumImage=Albumsbilde:
+Page.ImageBrowser.Album.Label.Title=Tittel:
+Page.ImageBrowser.Album.Label.Description=Beskrivelse:
+Page.ImageBrowser.Album.AlbumImage.Choose=Velg albumsbilde…
+Page.ImageBrowser.Album.Button.Save=Lagre album
+Page.ImageBrowser.Album.Button.Delete=Slett album
+Page.ImageBrowser.Image.Edit.Title=Endre bilde
+Page.ImageBrowser.Image.Title.Label=Tittel:
+Page.ImageBrowser.Image.Description.Label=Beskrivelse:
+Page.ImageBrowser.Image.Button.MoveLeft=◀
+Page.ImageBrowser.Image.Button.Save=Lagre bilde
+Page.ImageBrowser.Image.Button.MoveRight=►
+Page.ImageBrowser.Image.Delete.Title=Slett bilde
+Page.ImageBrowser.Image.Button.Delete=Slett bilde
+
+Page.CreateAlbum.Title=Lag album - Sone
+Page.CreateAlbum.Page.Title=Lag album
+Page.CreateAlbum.Error.NameMissing=Du ser ut til å ha glemt å skrive inn et navn til ditt nye album.
+
+Page.UploadImage.Title=Last opp bilde - Sone
+Page.UploadImage.Error.InvalidImage=Bildet du prøvde å laste opp har en ukjent filendelse. Vennligst bare bruk filer av typen JPEG (*.jpg eller *.jpeg) eller PNG (*.png).
+
+Page.EditImage.Title=Endre bilde - Sone
+
+Page.DeleteImage.Title=Slett bilde - Sone
+Page.DeleteImage.Page.Title=Slett bilde
+Page.DeleteImage.Text.ImageWillBeGone=Dette vil slette bildet «{image}» fra ditt album «{album}». Hvis det allerede er innsatt i Freenet kan det ikke fjernes. Vil du slette bildet?
+Page.DeleteImage.Button.Yes=Ja, slett bildet.
+Page.DeleteImage.Button.No=Nei, ikke slett bildet.
+
+Page.EditAlbum.Title=Endre album - Sone
+
+Page.DeleteAlbum.Title=Slett Album - Sone
+Page.DeleteAlbum.Page.Title=Slett Album
+Page.DeleteAlbum.Text.AlbumWillBeGone=Dette vil fjerne albumet ditt, «{title}». Vil du virkelig gjøre det?
+Page.DeleteAlbum.Button.Yes=Ja, slett album.
+Page.DeleteAlbum.Button.No=Nei, ikke slett album.
+
+Page.Trust.Title=Positiv tillit til Sone - Sone
+
+Page.Distrust.Title=Negativ tillit til Sone - Sone
+
+Page.Untrust.Title=Fjern tillit til Sone - Sone
+
+Page.MarkAsKnown.Title=Merk som kjent - Sone
+
+Page.Bookmark.Title=Bokmerke - Sone
+Page.Unbookmark.Title=Fjern bokmerke - Sone
+Page.Bookmarks.Title=Bokmerker - Sone
+Page.Bookmarks.Page.Title=Bokmerker
+Page.Bookmarks.Text.NoBookmarks=Du har ingen bokmerker for øyeblikket. Du kan bokmerke innlegg ved å klikke på stjernen under innlegget.
+Page.Bookmarks.Text.PostsNotLoaded=Noen av dine bokmerkede innlegg blir ikke vist fordi de ikke kunne bli lastet. Dette kan skje hvis du nylig har startet Sone på nytt eller hvis innlegget har blitt slettet. Hvis du er ganske sikker på at disse innleggene ikke eksisterer lenger, kan du {link}fjerne bokmerket{/link}.
+
+Page.Search.Title=Søk - Sone
+Page.Search.Page.Title=Søkeresultater
+Page.Search.Text.SoneHits=De følgende Sonene passet til søket.
+Page.Search.Text.PostHits=De følgende innleggene passet til søket.
+Page.Search.Text.NoHits=Ingen Soner eller innlegg passet til søket.
+
+Page.Rescue.Title=Redd Sone - Sone
+Page.Rescue.Page.Title=Redd Sone «{0}»
+Page.Rescue.Text.Description=Redningsmodus lar deg gjenopprette en tidligere utgave av din Sone. Dette kan være nødvendig hvis konfigurasjonen går tapt.
+Page.Rescue.Text.Procedure=Redningsmodus viker slik at den laster ned den siste innsatte utgaven av din Sone. Hvis nedlastingen går bra, vil denne utgaven bli lastet inn som din Sone. Den vil la deg kontrollere din profil, innlegg og svar og andre innstillinger (Dette kan gjøres fra et nytt vindu). Hvis dette ikke er den utgaven du ønsker å gjenopprette, ber du redningsmodus om å laste ned utgaven før.
+Page.Rescue.Text.Fetching=Sone-redderen laster foreløpig ned utgave {0} av din Sone.
+Page.Rescue.Text.Fetched=Sone-redderen har lastet ned utgave {0} av din Sone. Sjekk dine innlegg, svar og profil. Hvis du er fornøyd med redningen, kan du låse opp Sonen din.
+Page.Rescue.Text.FetchedLast=Sone-redderen har lastet ned den siste tilgjengelige utgaven. Hvis den ikke klarte å redde Sonen din, er det lite annet å gjøre.
+Page.Rescue.Text.NotFetched=Sone-redderen kunne ikke laste ned utgave {0} av din Sone. Enten prøv igjen på nytt med utgave {0}, eller prøv igjen med utgaven før.
+Page.Rescue.Label.NextEdition=Neste utgave:
+Page.Rescue.Button.Fetch=Hent utgave
+
+Page.NoPermission.Title=Ikke-autorisert tilgang - Sone
+Page.NoPermission.Page.Title=Ikke-autorisert tilgang
+Page.NoPermission.Text.NoPermission=Du prøvde å gjøre noe som du ikke har tilstrekkelige rettigheter til. Vennligst avstå fra slike handlinger i framtiden ellers vil vi bli tvunget til å ta til motgrep!
+
+Page.DismissNotification.Title=Fjern varsel - Sone
+
+Page.WotPluginMissing.Text.WotRequired=Fordi 'Web Of Trust' er en integrert del av Sone, må 'Web Of Trust'-tillegget bli lastet for å kunne kjøre Sone.
+Page.WotPluginMissing.Text.LoadPlugin=Vennligst gå til ${link}din Freenet-nodes tilleggs-side${/link} og aktiver 'Web Of Trust'-tillegget.
+
+Page.Logout.Title=Logg av - Sone
+
+Page.Invalid.Title=Ugyldig handling - Sone
+Page.Invalid.Page.Title=Ugyldig handling
+Page.Invalid.Text=En ugyldig handling ble gjort eller så var handlingens parametere ugyldig. Gå tilbake til {link}indeks{/link} og prøv på ny. Hvis feilmeldingen vedvarer har du sannsynligvis funnet en bug.
+
+View.Search.Button.Search=Søk
+
+View.CreateSone.Text.WotIdentityRequired=For å lage en Sone trenger du et pseudonym fra {link}'Web of Trust'-tillegget{/link}.
+View.CreateSone.Select.Default=Velg et pseudonym
+View.CreateSone.Text.NoIdentities=Du har ikke noen 'Web Of Trust'-pseudonym. Vennligst gå til {link}'Web of Trust'-tillegget{/link} og lag et pseudonym.
+View.CreateSone.Text.NoNonSoneIdentities=Du har ikke noen 'Web Of Trust'-pseudonym som ikke allerede har en Sone. Bruk en av de gjenværende 'Web Of Trust'-pseudonymene til å lage en ny Sone eller gå til {link}'Web of Trust'-tillegget{/link} for å lage et nytt pseudonym.
+View.CreateSone.Button.Create=Lag Sone
+View.CreateSone.Text.Error.NoIdentity=Du har ikke valgt et pseudonym.
+
+View.Sone.Label.LastUpdate=Siste oppdatering:
+View.Sone.Text.UnknownDate=ukjent
+View.Sone.Stats.Posts={0,number} {0,choice,0#innlegg|1#innlegg|1<innlegg}
+View.Sone.Stats.Replies={0,number} {0,choice,0#svar|1#svar|1<svar}
+View.Sone.Stats.Images={0,number} {0,choice,0#bilder|1#bilde|1<bilder}
+View.Sone.Button.UnlockSone=lås opp
+View.Sone.Button.UnlockSone.Tooltip=Tillatt at denne Sonen blir innsatt nå
+View.Sone.Button.LockSone=lås
+View.Sone.Button.LockSone.Tooltip=Forhindre denne Sonen fra å bli innsatt nå
+View.Sone.Button.UnfollowSone=ikke følg
+View.Sone.Button.FollowSone=følg
+View.Sone.Status.Modified=Denne Sonen ble endret og venter på å bli innsatt.
+View.Sone.Status.Unknown=Denne Sonen har ikke blitt lastet ned enda.
+View.Sone.Status.Idle=Denne Sonen er idle, dvs den blir ikke blitt innsatt eller lastet ned.
+View.Sone.Status.Downloading=Denne Sonen blir for øyeblikket lastet ned.
+View.Sone.Status.Inserting=Denne Sonen blir for øyeblikket innsatt.
+
+View.SoneMenu.Link.AllAlbums=alle album
+
+View.Post.UnknownAuthor=(ukjent)
+View.Post.WebOfTrustLink='web of trust'-profil
+View.Post.Permalink=link innlegg
+View.Post.PermalinkAuthor=link forfatter
+View.Post.Bookmarks.PostIsBookmarked=Innlegg er bokmerket. Klikk for å fjerne bokmerke
+View.Post.Bookmarks.PostIsNotBookmarked=Innlegget er ikke bokmerket. Klikk for å bokmerke.
+View.Post.DeleteLink=Slett
+View.Post.SendReply=Publiser svar!
+View.Post.Reply.DeleteLink=Slett
+View.Post.LikeLink=Liker
+View.Post.UnlikeLink=Fjern liker
+View.Post.ShowSource=Toggle Parser
+View.Post.NotDownloaded=Dette innlegget har ikke blitt lastet ned enda eller så er det slettet.
+View.Post.ShowMore=Vis mer
+View.Post.ShowLess=Vis mindre
+
+View.UpdateStatus.Text.ChooseSenderIdentity=Velg avsender-pseudonym
+
+View.Trust.Tooltip.Trust=Gi tillit til denne personen
+View.Trust.Tooltip.Distrust=Gi negativ tillit til denne personen
+View.Trust.Tooltip.Untrust=Fjern din tillit gitt til denne personen
+
+View.CreateAlbum.Title=Lag album
+View.CreateAlbum.Label.Name=Navn:
+View.CreateAlbum.Label.Description=Beskrivelse:
+
+View.UploadImage.Title=Last opp bilde
+View.UploadImage.Button.UploadImage=Last opp bilde
+View.UploadImage.Label.Description=Beskrivelse:
+View.UploadImage.Label.Title=Tittel:
+
+View.Time.InTheFuture=i framtiden
+View.Time.AFewSecondsAgo=noen få sekunder siden
+View.Time.HalfAMinuteAgo=omtrent et halvt minutt siden
+View.Time.AMinuteAgo=omtrent et minutt siden
+View.Time.XMinutesAgo=${min} minutter siden
+View.Time.HalfAnHourAgo=en halvtime siden
+View.Time.AnHourAgo=omtrent en time siden
+View.Time.XHoursAgo=${hour} timer siden
+View.Time.ADayAgo=omtrent en dag siden
+View.Time.XDaysAgo=${day} dager siden
+View.Time.AWeekAgo=omtrent en uke siden
+View.Time.XWeeksAgo=${week} uker siden
+View.Time.AMonthAgo=omtrent en måned siden
+View.Time.XMonthsAgo=${month} måneder siden
+View.Time.AYearAgo=omtrent et år siden
+View.Time.XYearsAgo=${year} år siden
+
+WebInterface.DefaultText.StatusUpdate=Hva tenker du på?
+WebInterface.DefaultText.Message=Skriv et innlegg…
+WebInterface.DefaultText.Reply=Skriv et svar…
+WebInterface.DefaultText.FirstName=Fornavn
+WebInterface.DefaultText.MiddleName=Mellomnavn
+WebInterface.DefaultText.LastName=Etternavn
+WebInterface.DefaultText.BirthDay=Dag
+WebInterface.DefaultText.BirthMonth=Måned
+WebInterface.DefaultText.BirthYear=År
+WebInterface.DefaultText.FieldName=Feltnavn
+WebInterface.DefaultText.Option.InsertionDelay=Tiden å vente fra en Sone er endret før den settes inn (i sekunder)
+WebInterface.DefaultText.Search=Hva leter du etter?
+WebInterface.DefaultText.CreateAlbum.Name=Album tittel
+WebInterface.DefaultText.CreateAlbum.Description=Album beskrivelse
+WebInterface.DefaultText.EditAlbum.Title=Albumtittel
+WebInterface.DefaultText.EditAlbum.Description=Albumbeskrivelse
+WebInterface.DefaultText.UploadImage.Description=Bildebeskrivelse
+WebInterface.DefaultText.UploadImage.Title=Bildetittel
+WebInterface.DefaultText.EditImage.Description=Bildebeskrivelse
+WebInterface.DefaultText.EditImage.Title=Bildetittel
+WebInterface.DefaultText.Option.PostsPerPage=Antall innlegg å vise på en side
+WebInterface.DefaultText.Option.CharactersPerPost=Antall tegn et innlegg må ha for å bli skjult.
+WebInterface.DefaultText.Option.PostCutOffLength=Antall tegn som vises når et innlegg blir skjult
+WebInterface.DefaultText.Option.PositiveTrust=Positiv tillit å gi
+WebInterface.DefaultText.Option.NegativeTrust=Negativ tillit å gi
+WebInterface.DefaultText.Option.TrustComment=Kommentaren til 'Web Of Trust'
+WebInterface.Button.Comment=Kommenter
+WebInterface.Confirmation.DeletePostButton=Ja, slett!
+WebInterface.Confirmation.DeleteReplyButton=Ja, slett!
+WebInterface.SelectBox.Choose=Velg…
+WebInterface.SelectBox.Yes=Ja
+WebInterface.SelectBox.No=Nei
+WebInterface.ClickToShow.Replies=Klikk her for å vise skjulte svar.
+WebInterface.VersionInformation.CurrentVersion=Gjeldende utgave:
+WebInterface.VersionInformation.LatestVersion=Siste utgave:
+
+Notification.ClickHereToRead=Klikk her for å lese hele varslingen.
+Notification.FirstStart.Text=Dette ser ut til å være første gang du starter Sone. For å starte, lag en ny Sone fra et 'Web Of Trust'-pseudonym og start å følge andre Soner.
+Notification.Startup.Text=Sone starter opp. Det kan ta en stund å motta alle pseudonymer og Soner fra 'Web Of Trust'. Hvis du mangler noen, vennligst vent, de vil sannsynligvis dukke opp snart.
+Notification.ConfigNotRead.Text=Konfigurasjonsfilen «sone.properties» kunne ikke bli lest, sannsynligvis fordi den ikke ble lagret riktig. Dette kan skje i versjoner før Sone 0.3.3 og det er ingen ting du kan gjøre med det.
+Notification.Button.Dismiss=Fjern varsel
+Notification.NewSone.ShortText=Nye Soner har blitt oppdaget:
+Notification.NewSone.Text=Nye Soner har blitt oppdaget:
+Notification.NewPost.ShortText=Nye innlegg har blitt oppdaget.
+Notification.NewPost.Text=Nye innlegg har blitt oppdaget av de følgende Sonene:
+Notification.NewPost.Button.MarkRead=Merk som lest
+Notification.NewReply.ShortText=Nye svar har blitt oppdaget.
+Notification.NewReply.Text=Nye svar har blitt oppdaget for innlegg av følgende Soner:
+Notification.SoneIsBeingRescued.Text=De følgende Sonene blir for øyeblikket reddet:
+Notification.SoneRescued.Text=De følgende Sonene har blitt reddet:
+Notification.SoneRescued.Text.RememberToUnlock=Husk å kontroller innlegg og svar du har publisert og ikke glem å lås opp dine Soner!
+Notification.LockedSones.Text=De følgende Sonene har vært låst i mer enn 5 minutter. Vennligst sjekk om du virkelig ønsker å beholde disse Sonene låst:
+Notification.NewVersion.Text=Utgave {version} av sone-tillegget ble funnet. Last det ned fra USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}​!
+Notification.InsertingImages.Text=De følgende bildene blir lastet opp:
+Notification.InsertedImages.Text=De følgende bildene har blitt lastet opp:
+Notification.ImageInsertFailed.Text=De følgende bildene kunne ikke bli innsatt:
+Notification.Mention.ShortText=Du har blitt nevnt:
+Notification.Mention.Text=Du har blitt nevnt i følgende innlegg:
+Notification.SoneInsert.Duration={0,number} {0,choice,0#sekund|1#sekund|1<sekunder}
+
+# Updates: 7-8, 99-101, 238, 240, 267, 269, 271, 416
diff --git a/src/main/resources/i18n/sone.ru.properties b/src/main/resources/i18n/sone.ru.properties
new file mode 100644 (file)
index 0000000..bc43303
--- /dev/null
@@ -0,0 +1,448 @@
+Navigation.Menu.Sone.Name=Sone
+Navigation.Menu.Sone.Tooltip=Дополнение социальной сети для Freenet
+Navigation.Menu.Sone.Item.Login.Name=Вход
+Navigation.Menu.Sone.Item.Login.Tooltip=Войти в свой Sone
+Navigation.Menu.Sone.Item.Index.Name=Ваш Sone
+Navigation.Menu.Sone.Item.Index.Tooltip=Создать свой Sone
+Navigation.Menu.Sone.Item.New.Name=Новые сообщения и ответы
+Navigation.Menu.Sone.Item.New.Tooltip=Показывает новые сообщения и ответы
+Navigation.Menu.Sone.Item.CreateSone.Name=Создать Sone
+Navigation.Menu.Sone.Item.CreateSone.Tooltip=Создать новый Sone
+Navigation.Menu.Sone.Item.KnownSones.Name=Известные Sone
+Navigation.Menu.Sone.Item.KnownSones.Tooltip=Показывает все известные Sone
+Navigation.Menu.Sone.Item.Bookmarks.Name=Закладки
+Navigation.Menu.Sone.Item.Bookmarks.Tooltip=Показать сообщения в закладках
+Navigation.Menu.Sone.Item.EditProfile.Name=Редактировать профиль
+Navigation.Menu.Sone.Item.EditProfile.Tooltip=Редактировать профиль вашего Sone
+Navigation.Menu.Sone.Item.ImageBrowser.Name=Изображения
+Navigation.Menu.Sone.Item.ImageBrowser.Tooltip=Управляет вашими изображениями
+Navigation.Menu.Sone.Item.DeleteSone.Name=Удалить Sone
+Navigation.Menu.Sone.Item.DeleteSone.Tooltip=Удаляет текущий Sone
+Navigation.Menu.Sone.Item.Logout.Name=Выйти
+Navigation.Menu.Sone.Item.Logout.Tooltip=Выходит из текущего Sone
+Navigation.Menu.Sone.Item.Options.Name=Настройки
+Navigation.Menu.Sone.Item.Options.Tooltip=Настройки дополнения Sone
+Navigation.Menu.Sone.Item.Rescue.Name=Восстановление
+Navigation.Menu.Sone.Item.Rescue.Tooltip=Восстановить Sone
+Navigation.Menu.Sone.Item.About.Name=О дополнении
+Navigation.Menu.Sone.Item.About.Tooltip=Информация о Sone
+
+Page.About.Title=О дополнении - Sone
+Page.About.Page.Title=О дополнении
+Page.About.Flattr.Description=Если вам нравится Sone и вы хотите вознаградить меня, вы можете воспользоваться кнопкой Flattr внизу каждой страницы. Flattr - это неанонимный микроплатеж, который работает как интернет-чаевые, где сумма, которую каждый пользователь может потратить, ограничена (самое меньшее - 2 € в месяц). Больше информации вы можете найти на странице {link}flattr.com{/link}.
+Page.About.Homepage.Title=Домашняя страница
+Page.About.Homepage.Description=Вы можете найти больше информации и исходный код Sone на {link}домашней странице{/link}
+Page.About.License.Title=Лицензия
+
+Page.Options.Title=Настройки - Sone
+Page.Options.Page.Title=Настройки
+Page.Options.Page.Description=Эти настройки влияют на поведение дополнения Sone во время работы
+Page.Options.Section.SoneSpecificOptions.Title=Настройки, специфичные для Sone
+Page.Options.Section.SoneSpecificOptions.NotLoggedIn=Эти настройки доступны, только если вы выполнили {link}вход{/link}
+Page.Options.Section.SoneSpecificOptions.LoggedIn=Эти настройки доступны, только когда вы выполнили вход, и они применимы только к Sone, под именем которого вы вошли.
+Page.Options.Option.AutoFollow.Description=Если обнаружен новый Sone, автоматически подписываться на него. Обратите внимание, что эта эта настройка позволит подписываться только на Sone, которые обнаружены после ее активации!
+Page.Options.Option.EnableSoneInsertNotifications.Description=Если включено, уведомления будут показываться каждый раз, когда ваш Sone выгружается или завершает выгрузку.
+Page.Options.Option.ShowNotificationNewSones.Description=Показывать уведомления для новых Sone.
+Page.Options.Option.ShowNotificationNewPosts.Description=Показывать уведомления для новых сообщений.
+Page.Options.Option.ShowNotificationNewReplies.Description=Показывать уведомления для новых ответов.
+Page.Options.Section.AvatarOptions.Title=Настройки аватара.
+Page.Options.Option.ShowAvatars.Description=Вы можете отключить пользовательские аватары здесь, в зависимости от выбранных критериев. Если аватар для Sone отключен, вместо этого будет показан автоматически сгенерированный аватар.
+Page.Options.Option.ShowAvatars.Never.Description=Никогда не показывать пользовательские аватары.
+Page.Options.Option.ShowAvatars.Followed.Description=Показывать аватары только для Sone, на которые вы подписаны.
+Page.Options.Option.ShowAvatars.ManuallyTrusted.Description=Показывать аватары только для Sone, которым вы вручную задали значение доверия выше 0.
+Page.Options.Option.ShowAvatars.Trusted.Description=Показывать аватары только для Sone, значение доверия которых выше 0.
+Page.Options.Option.ShowAvatars.Always.Description=Всегда показывать пользовательские аватары. Предупреждение: некоторые аватары могут содержать раздражающие или оскорбительные изображения.
+Page.Options.Section.RuntimeOptions.Title=Поведение во время работы.
+Page.Options.Option.InsertionDelay.Description=Количество секунд, в течение которых выгрузчик Sone ожидает после изменения Sone до того, как он будет выгружен.
+Page.Options.Option.PostsPerPage.Description=Количество сообщений, которое должно быть показно на странице до того, как будут показаны кнопки переключения страниц.
+Page.Options.Option.CharactersPerPost.Description=Количество символов сообщения, которые должны быть показаны до того, как оно будет обрезано и будет показана ссылка для его раскрытия (-1 для отключения). Фактическая длина обрезанного сообщения задается нижеследующей настройкой.
+Page.Options.Option.PostCutOffLength.Description=Количество символов, которые показываются, если сообщение посчитано слишком длинным (см. настройку выше).
+Page.Options.Option.RequireFullAccess.Description=Запрещать доступ к Sone любому хосту, которому не был дан полный доступ.
+Page.Options.Section.TrustOptions.Title=Настройки доверия
+Page.Options.Option.PositiveTrust.Description=Количество положительного доверия, которое вы хотите назначать другим Sone, нажимая галочку под сообщением или ответом.
+Page.Options.Option.NegativeTrust.Description=Количество доверия, которое вы хотите назначить другим Sone, нажимая красный X под сообщением или ответом. Это значение должно быть отрицательным.
+Page.Options.Option.TrustComment.Description=Комментарий, который будет установлен в web of trust для любого доверия, назначенного из Sone.
+Page.Options.Section.FcpOptions.Title=Настройка интерфейса FCP
+Page.Options.Option.FcpInterfaceActive.Description=Активировать интерфейс FCP, чтобы позволить другим дополнениям и удаленным клиентам получать доступ к вашему дополнению Sone.
+Page.Options.Option.FcpFullAccessRequired.Description=Требовать соединение FCP от разрешенных хостов(см. {link}конфигурацию узла, секция "FCP"{/link}).
+Page.Options.Option.FcpFullAccessRequired.Value.No=Нет
+Page.Options.Option.FcpFullAccessRequired.Value.Writing=Для доступа на запись
+Page.Options.Option.FcpFullAccessRequired.Value.Always=Всегда
+Page.Options.Section.Cleaning.Title=Очистка
+Page.Options.Option.ClearOnNextRestart.Description=Сбрасывает настройки дополнения Sone во время следующего перезапуска. Предупреждение! {strong}Это уничтожит все ваши Sone{/strong}, так что удостоверьтесь, что вы сохранили резервные копии всего, что вам еще нужно! Кроме того, вам нужно установить следующую настройку в значение true, чтобы действительно это сделать.
+Page.Options.Option.ReallyClearOnNextRestart.Description=Эта опция должна быть установлена в "yes", если вы действительно, {strong}действительно{/strong} хотите очистить настройки дополнения во время следующего перезапуска.
+Page.Options.Warnings.ValueNotChanged=Эта настройка не была изменена, потому что заданное вами значение было неверным.
+Page.Options.Button.Save=Сохранить
+
+Page.Login.Title=Вход - Sone
+Page.Login.Page.Title=Вход
+Page.Login.Label.SelectSone=Выберите Sone:
+Page.Login.Option.NoSone=Выбрать Sone…
+
+Page.Login.CreateSone.Title=Создать Sone
+
+Page.CreateSone.Title=Создать Sone - Sone
+
+Page.DeleteSone.Title=Удалить Sone - Sone
+Page.DeleteSone.Page.Title=Удалить Sone “{sone}”?
+Page.DeleteSone.Page.Description=Это не удалит Sone из Freenet (потому что это невозможно), это только отключит вашу личность web of trust от Sone.
+Page.DeleteSone.Button.Yes=Да, удалить.
+Page.DeleteSone.Button.No=Нет, не удалять.
+
+Page.Index.Title=Ваш Sone - Sone
+Page.Index.Label.Text=Текст сообщения:
+Page.Index.Label.Sender=Отправитель:
+Page.Index.Button.Post=Отправить!
+Page.Index.PostList.Title=Лента сообщений
+Page.Index.PostList.Text.NoPostYet=Никто еще не написал ни одного сообщения. Вам, наверное, следует начать это прямо сейчас!
+
+Page.New.Title=Новые сообщения и ответы - Sone
+Page.New.Page.Title=Новые сообщения и ответы
+Page.New.NothingNew=В данный момент ничего нового нет.
+
+Page.KnownSones.Title=Известные Sone - Sone
+Page.KnownSones.Page.Title=Известные Sone
+Page.KnownSones.Text.NoKnownSones=В данный момент нет известных Sone, отвечающих заданному фильтру
+Page.KnownSones.Label.Sort=Сортировка:
+Page.KnownSones.Label.FilterSones=Фильтровать Sone:
+Page.KnownSones.Sort.Field.Name=Имя
+Page.KnownSones.Sort.Field.LastActivity=Последняя активность
+Page.KnownSones.Sort.Field.Posts=Количество сообщений
+Page.KnownSones.Sort.Field.Images=Количество изображений
+Page.KnownSones.Sort.Order.Ascending=По возрастанию
+Page.KnownSones.Sort.Order.Descending=По убыванию
+Page.KnownSones.Filter.Followed=Показывать только Sone, на которые вы подписаны
+Page.KnownSones.Filter.NotFollowed=Скрыть Sone, на которые вы подписаны
+Page.KnownSones.Filter.New=Показывать только новые Sone
+Page.KnownSones.Filter.NotNew=Скрыть новые Sone
+Page.KnownSones.Button.Apply=Применить
+Page.KnownSones.Button.FollowAllSones=Подписаться на все Sone на этой странице
+Page.KnownSones.Button.UnfollowAllSones=Снять подписку со всех Sone на этой странице
+
+Page.EditProfile.Title=Редактировать профиль - Sone
+Page.EditProfile.Page.Title=Редактировать профиль
+Page.EditProfile.Page.Description=На этой странице вы можете ввести данные своего профиля.
+Page.EditProfile.Page.Hint.Optionality=И помните, каждое поле этого профиля опционально! Вы не обязаны вводить ни единой вещи здесь! Кроме того, все, что вы здесь введете, будет скорее всего храниться во Freenet очень долго!
+Page.EditProfile.Label.FirstName=Имя:
+Page.EditProfile.Label.MiddleName=Отчество:
+Page.EditProfile.Label.LastName=Фамилия:
+Page.EditProfile.Birthday.Title=Дата рождения
+Page.EditProfile.Birthday.Label.Day=День:
+Page.EditProfile.Birthday.Label.Month=Месяц:
+Page.EditProfile.Birthday.Label.Year=Год:
+Page.EditProfile.Avatar.Title=Аватар
+Page.EditProfile.Avatar.Description=Вы можете выбрать одно из загруженных изображений для показа в качестве аватара. Оно не должно быть больше, чем 64x64 пикселя, потому что это самый большой размер, показываемый другим людям (80x80 пикселей используются как заголовок страницы).
+Page.EditProfile.Avatar.Delete=Без аватара
+Page.EditProfile.Fields.Title=Пользовательские поля
+Page.EditProfile.Fields.Description=Здесь вы можете ввести в свой профиль пользовательские поля. Эти поля могут содержать все, что вы хотите и быть такими краткими или много словными, как вы хотите. Просто помните, что когда дело доходит до анонимности, иногда чем меньше - тем лучше.
+Page.EditProfile.Fields.Button.Edit=изменить
+Page.EditProfile.Fields.Button.MoveUp=переместить вверх
+Page.EditProfile.Fields.Button.MoveDown=переместить вниз
+Page.EditProfile.Fields.Button.Delete=удалить
+Page.EditProfile.Fields.Button.ReallyDelete=действительно удалить
+Page.EditProfile.Fields.AddField.Title=Добавить поле
+Page.EditProfile.Fields.AddField.Label.Name=Название:
+Page.EditProfile.Fields.AddField.Button.AddField=Добавить поле
+Page.EditProfile.Button.Save=Сохранить профиль
+Page.EditProfile.Error.DuplicateFieldName=Название поля "{fieldName}" уже существует.
+
+Page.EditProfileField.Title=Изменить поле профиля - Sone
+Page.EditProfileField.Page.Title=Изменить поле профиля
+Page.EditProfileField.Text=Введите новое имя для этого поля профиля.
+Page.EditProfileField.Error.DuplicateFieldName=Имя поля, которое вы ввели, уже существует.
+Page.EditProfileField.Button.Save=Изменить
+Page.EditProfileField.Button.Reset=Вернуть старое имя
+Page.EditProfileField.Button.Cancel=Не изменять имя
+
+Page.DeleteProfileField.Title=Удалить поле профиля - Sone
+Page.DeleteProfileField.Page.Title=Удалить поле профиля
+Page.DeleteProfileField.Text=Вы действительно хотите удалить это поле профиля?
+Page.DeleteProfileField.Button.Yes=Да, удалить
+Page.DeleteProfileField.Button.No=Нет, не удалять
+
+Page.CreatePost.Title=Создать сообщение - Sone
+Page.CreatePost.Page.Title=Создать сообщение
+Page.CreatePost.Label.Text=Текст сообщения:
+Page.CreatePost.Button.Post=Отправить!
+Page.CreatePost.Error.EmptyText=Вы не ввели никакого текста, очень жаль. Вы должны попытаться написать больше!
+
+Page.CreateReply.Title=Создать ответ - Sone
+Page.CreateReply.Page.Title=Создать ответ
+Page.CreateReply.Error.EmptyText=Вы не ввели никакого текста, очень жаль. Вы должны попытаться написать больше!
+Page.CreateReply.Label.Text=Текст ответа:
+Page.CreateReply.Button.Post=Отправить ответ!
+
+Page.ViewSone.Title=Просмотреть Sone - Sone
+Page.ViewSone.Page.TitleWithoutSone=Просмотреть неизвестный Sone
+Page.ViewSone.NoSone.Description=В данный момент нет известного Sone с ID {sone}. Если вы искали конкретный Sone, удостоверьтесь, что он видим в вашем web of trust!
+Page.ViewSone.UnknownSone.Description=Этот Sone еще не был извлечен. Пожалуйста проверьте еще раз через некоторое время.
+Page.ViewSone.UnknownSone.LinkToWebOfTrust=Несмотря на то, что Sone еще не известен, его профиль web of trust может уже быть доступен:
+Page.ViewSone.WriteAMessage=Вы можете написать сообщение этому Sone здесь. Обратите внимание, что все смогут прочитать это сообщение!
+Page.ViewSone.PostList.Title=Сообщение {sone}
+Page.ViewSone.PostList.Text.NoPostYet=Этот Sone еще ничего не написал.
+Page.ViewSone.Profile.Title=Профиль
+Page.ViewSone.Profile.Label.Name=Имя
+Page.ViewSone.Profile.Label.Albums=Альбомы
+Page.ViewSone.Profile.Albums.Text.All=Все альбомы
+Page.ViewSone.Profile.Name.WoTLink=профиль web of trust
+Page.ViewSone.Replies.Title=Сообщения, на которые {sone} ответил
+
+Page.ViewPost.Title=Просмотр сообщения - Sone
+Page.ViewPost.Page.Title=Просмотр сообщения {sone}
+Page.ViewPost.Page.TitleUnknownSone=Просмотр неизвестного сообщения
+Page.ViewPost.Text.UnknownPost=Это сообщение еще не было загружено.
+
+Page.Like.Title=Мне нравится - Sone
+Page.Unlike.Title=Мне не нравится - Sone
+
+Page.DeletePost.Title=Удалить Sone - Sone
+Page.DeletePost.Page.Title=Удалить Sone
+Page.DeletePost.Text.PostWillBeGone=Удаление сообщение удалит его из вашего Sone. Это не удалит его из Freenet, потому что это невозможно. Старые версии вашего Sone будут всегда включать удаленное сообщение.
+Page.DeletePost.Button.Yes=Да, удалить.
+Page.DeletePost.Button.No=Нет, не удалять.
+
+Page.DeleteReply.Title=Удалить ответ - Sone
+Page.DeleteReply.Page.Title=Удалить ответ
+Page.DeleteReply.Text.PostWillBeGone=Удаление ответа удалит его из вашего Sone. Это не удалит его из Freenet, потому что это невозможно. Старые версии вашего Sone будут всегда включать удаленный ответ.
+Page.DeleteReply.Button.Yes=Да, удалить.
+Page.DeleteReply.Button.No=Нет, не удалять.
+
+Page.LockSone.Title=Заблокировать Sone - Sone
+
+Page.UnlockSone.Title=Разблокировать Sone - Sone
+
+Page.FollowSone.Title=Подписаться на Sone - Sone
+
+Page.UnfollowSone.Title=Отменить подписку на Sone - Sone
+
+Page.ImageBrowser.Title=Менеджер изображений - Sone
+Page.ImageBrowser.Album.Title=Альбом "{album}"
+Page.ImageBrowser.Album.Error.NotFound.Text=Заданный альбом не может быть найден. Возможно, он еще не был загружен или был удален.
+Page.ImageBrowser.Sone.Title=Альбомы {sone}
+Page.ImageBrowser.Sone.Error.NotFound.Text=Требуемый Sone не может быть найден. Возможно, он еще не был загружен
+Page.ImageBrowser.Header.Albums=Альбомы
+Page.ImageBrowser.Header.Images=Изображения
+Page.ImageBrowser.Link.All=Все Sone
+Page.ImageBrowser.CreateAlbum.Button.CreateAlbum=Создать альбом
+Page.ImageBrowser.Album.Edit.Title=Редактировать альбом
+Page.ImageBrowser.Album.Delete.Title=Удалить альбом
+Page.ImageBrowser.Album.Label.AlbumImage=Изображение альбома:
+Page.ImageBrowser.Album.Label.Title=Название:
+Page.ImageBrowser.Album.Label.Description=Описание:
+Page.ImageBrowser.Album.AlbumImage.Choose=Выберите изображение альбома…
+Page.ImageBrowser.Album.Button.Save=Сохранить альбом
+Page.ImageBrowser.Album.Button.Delete=Удалить альбом
+Page.ImageBrowser.Image.Edit.Title=Изменить изображение
+Page.ImageBrowser.Image.Title.Label=Название:
+Page.ImageBrowser.Image.Description.Label=Описание:
+Page.ImageBrowser.Image.Button.MoveLeft=◀
+Page.ImageBrowser.Image.Button.Save=Сохранить изображение
+Page.ImageBrowser.Image.Button.MoveRight=►
+Page.ImageBrowser.Image.Delete.Title=Удалить изображение
+Page.ImageBrowser.Image.Button.Delete=Удалить изображение
+
+Page.CreateAlbum.Title=Создать альбом - Sone
+Page.CreateAlbum.Page.Title=Создать альбом
+Page.CreateAlbum.Error.NameMissing=Видимо, вы забыли ввести название для вашего нового альбома.
+
+Page.UploadImage.Title=Загрузить изображение - Sone
+Page.UploadImage.Error.InvalidImage=Изображение, которое вы пытаетесь загрузить, не может быть распознано. Пожалуйста, загружайте только изображения JPEG (*.jpg или *.jpeg) или PNG (*.png).
+
+Page.EditImage.Title=Изменить изображение - Sone
+
+Page.DeleteImage.Title=Удалить изображение - Sone
+Page.DeleteImage.Page.Title=Удалить изображение
+Page.DeleteImage.Text.ImageWillBeGone=Это удалит изображение "{image}" из вашего альбома "{album}". Если оно уже было выгружено во Freenet, оно не может быть насильно оттуда удалено. Вы хотите удалить изображение?
+Page.DeleteImage.Button.Yes=Да, удалить изображение.
+Page.DeleteImage.Button.No=Нет, не удалять изображение.
+
+Page.EditAlbum.Title=Редактировать альбом - Sone
+
+Page.DeleteAlbum.Title=Удалить альбом - Sone
+Page.DeleteAlbum.Page.Title=Удалить альбом
+Page.DeleteAlbum.Text.AlbumWillBeGone=Это удалит альбом "{title}". Вы действительно хотите это сделать?
+Page.DeleteAlbum.Button.Yes=Да, удалить альбом.
+Page.DeleteAlbum.Button.No=Нет, не удалять альбом.
+
+Page.Trust.Title=Доверять Sone - Sone
+
+Page.Distrust.Title=Не доверять Sone - Sone
+
+Page.Untrust.Title=Отменить доверие к Sone - Sone
+
+Page.MarkAsKnown.Title=Отметить как известный - Sone
+
+Page.Bookmark.Title=Добавить в закладки - Sone
+Page.Unbookmark.Title=Удалить из закладок - Sone
+Page.Bookmarks.Title=Закладки - Sone
+Page.Bookmarks.Page.Title=Закладки
+Page.Bookmarks.Text.NoBookmarks=В данный момент у вас не определено ни одной закладки. Вы можете добавить сообщения в закладки, нажимая на звезду под сообщением.
+Page.Bookmarks.Text.PostsNotLoaded=Некоторые из ваших закладок не были показаны, потому что они не могут быть загружены. Это происходит, если вы недавно перезапускали Sone или исходный Sone удалил сообщение. Если у вас есть причины считать, что эти сообщения больше не существуют, вы можете {link}удалить их из закладок{/link}
+
+Page.Search.Title=Поиск - Sone
+Page.Search.Page.Title=Результаты поиска
+Page.Search.Text.SoneHits=Следующие Sone отвечают критериям поиска.
+Page.Search.Text.PostHits=Следующие сообщения отвечают критериям поиска.
+Page.Search.Text.NoHits=Не найдено Sone или сообщений, отвечающих критериям поиска.
+
+Page.Rescue.Title=Восстановление Sone - Sone
+Page.Rescue.Page.Title=Восстановление Sone "{0}"
+Page.Rescue.Text.Description=Режим восстановления позволяет вам восстановить предыдущие версии вашего Sone. Это может быть необходимо, если ваши настройки были потеряны.
+Page.Rescue.Text.Procedure=Режим восстановления работает с помощью загрузки последней выгруженной редакции вашего Sone. Если редакция была успешно загружена, она будет загружена в ваш Sone, позволяя вам контролировать ваши сообщения, профиль и другие настройки (вы можете сделать это в другой вкладке или окне браузера). Если загруженная редакция - не то, которое вы хотите восстановить, укажите Режиму восстановления загрузить следующую по давности редакцию ниже.
+Page.Rescue.Text.Fetching=Восстановитель Sone в данный момент загружает редакцию {0} вашего Sone.
+Page.Rescue.Text.Fetched=Восстановитель Sone скачал редакцию {0} вашего Sone. Пожалуйста проверьте свои сообщения, ответы и профиль.
+Page.Rescue.Text.FetchedLast=Восстановитель Sone скачал последнюю доступную редакцию. Если ему не удалось восстановить ваш Sone, у вас кончились варианты действий.
+Page.Rescue.Text.NotFetched=Восстановитель Sone не смог скачать редакцию {0} вашего Sone. Пожалуйста, либо попытайтесь снова с редакцией {0}, либо попробуйте более старую редакцию.
+Page.Rescue.Label.NextEdition=Следующая редакция:
+Page.Rescue.Button.Fetch=Загрузить редакцию
+
+Page.NoPermission.Title=Неавторизованный доступ - Sone
+Page.NoPermission.Page.Title=Неавторизованный доступ
+Page.NoPermission.Text.NoPermission=Вы пытались сделать что-то, для чего у вас недостаточно авторизации. Пожалуйска воздержитесь от подобных действий в будущем или мы будем вынуждены применить контр-меры!
+
+Page.DismissNotification.Title=Скрыть уведомление - Sone
+
+Page.WotPluginMissing.Text.WotRequired=Так как Web of Trust - неотъемлимая часть Sone, дополнение Web of Trust должно быть запущего для работы Sone.
+Page.WotPluginMissing.Text.LoadPlugin=Пожалуйска загрузите дополнение Web of Trusr в {link}менеджере дополнений{/link}.
+
+Page.Logout.Title=Выйти - Sone
+
+Page.Invalid.Title=Произведено неверное действие - Sone
+Page.Invalid.Page.Title=Произведено неверное действие
+Page.Invalid.Text=Было произведено неверное действие, или верное действие с неверными параметрами. Пожалуйста, вернитесь на {link}главную страницу{/link} и попытайтесь снова. Если ошибка повторяется, вы, вероятно, обнаружили баг.
+
+View.Search.Button.Search=Поиск
+
+View.CreateSone.Text.WotIdentityRequired=Чтобы создать Sone, вам необходима личность от дополнения {link}Web of Trust{/link}.
+View.CreateSone.Select.Default=Выбрать личность
+View.CreateSone.Text.NoIdentities=У вас нет ни одной личности Web of Trust. Пожалуйста, посетите страницу дополнения {link}Web of Trust{/link} и создайте личность
+View.CreateSone.Text.NoNonSoneIdentities=У вас нет ни одной личности Web of Trust которые еще не подключены к Sone. Используйте один из оставшихся личностей Web of Trust, чтобы создать новый Sone или посетите страницу {link}Web of Trust{/link}, чтобы создать новую личность.
+View.CreateSone.Button.Create=Создать Sone
+View.CreateSone.Text.Error.NoIdentity=Вы не выбрали личность.
+
+View.Sone.Label.LastUpdate=Последнее обновление:
+View.Sone.Text.UnknownDate=неизвестно
+View.Sone.Stats.Posts={0,number} {0,choice,0#сообщений|1#сообщение|2#сообщения|4<сообщений}
+View.Sone.Stats.Replies={0,number} {0,choice,0#ответов|1#ответ|2#ответа|4<ответов}
+View.Sone.Stats.Images={0,number} {0,choice,0#изображений|1#изображение|2#изображения|4<изображений}
+View.Sone.Button.UnlockSone=разблокировать
+View.Sone.Button.UnlockSone.Tooltip=Позволить этому Sone быть выгруженный сейчас
+View.Sone.Button.LockSone=заблокировать
+View.Sone.Button.LockSone.Tooltip=Запрещает этому Sone выгружаться сейчас
+View.Sone.Button.UnfollowSone=отменить подписку
+View.Sone.Button.FollowSone=подписаться
+View.Sone.Status.Modified=Этот Sone был изменен и ожидает выгрузки.
+View.Sone.Status.Unknown=Этот Sone еще не был получен.
+View.Sone.Status.Idle=Этот Sone находится в режиме ожидания, т.е. не выгружается и не загружается.
+View.Sone.Status.Downloading=Этот Sone сейчас загружается.
+View.Sone.Status.Inserting=Этот Sone сейчас выгружается.
+
+View.SoneMenu.Link.AllAlbums=все альбомы
+
+View.Post.UnknownAuthor=(неизвестно)
+View.Post.WebOfTrustLink=профиль web of trust
+View.Post.Permalink=ссылка на сообщение
+View.Post.PermalinkAuthor=ссылка на автора
+View.Post.Bookmarks.PostIsBookmarked=Сообщение в закладках. Нажмите, чтобы удалить из закладок.
+View.Post.Bookmarks.PostIsNotBookmarked=Сообщение не в закладках. Нажмите, чтобы добавить в закладки.
+View.Post.DeleteLink=Удалить
+View.Post.SendReply=Отправить ответ!
+View.Post.Reply.DeleteLink=Удалить
+View.Post.LikeLink=Мне нравится
+View.Post.UnlikeLink=Мне не нравится
+View.Post.ShowSource=Вкл/выкл парсер
+View.Post.NotDownloaded=Это сообщение еще не было загружено или было удалено.
+View.Post.ShowMore=показать больше
+View.Post.ShowLess=показать меньше
+
+View.UpdateStatus.Text.ChooseSenderIdentity=выбрать личность отправителя
+
+View.Trust.Tooltip.Trust=Доверять этому человека
+View.Trust.Tooltip.Distrust=Назначить этому человеку отрицательное доверие
+View.Trust.Tooltip.Untrust=Отменить доверие к этому человеку
+
+View.CreateAlbum.Title=Создать альбом
+View.CreateAlbum.Label.Name=Название:
+View.CreateAlbum.Label.Description=Описание:
+
+View.UploadImage.Title=Загрузить изображение
+View.UploadImage.Label.Title=Название:
+View.UploadImage.Label.Description=Описание:
+View.UploadImage.Button.UploadImage=Загрузить изображение
+
+View.Time.InTheFuture=в будущем
+View.Time.AFewSecondsAgo=несколько секунд назад
+View.Time.HalfAMinuteAgo=около полминуты назад
+View.Time.AMinuteAgo=около минуты назад
+View.Time.XMinutesAgo=${min} минут назад
+View.Time.HalfAnHourAgo=полчаса назад
+View.Time.AnHourAgo=около часа назад
+View.Time.XHoursAgo=${hour} часов назад
+View.Time.ADayAgo=около дня назад
+View.Time.XDaysAgo=${day} дней назад
+View.Time.AWeekAgo=около недели назад
+View.Time.XWeeksAgo=${week} недель назад
+View.Time.AMonthAgo=около месяца назад
+View.Time.XMonthsAgo=${month} месяцев назад
+View.Time.AYearAgo=около года назад
+View.Time.XYearsAgo=${year} лет назад
+
+WebInterface.DefaultText.StatusUpdate=Что у вас на уме?
+WebInterface.DefaultText.Message=Написать сообщение…
+WebInterface.DefaultText.Reply=Написать ответ…
+WebInterface.DefaultText.FirstName=Имя
+WebInterface.DefaultText.MiddleName=Отчество
+WebInterface.DefaultText.LastName=Фамилия
+WebInterface.DefaultText.BirthDay=День
+WebInterface.DefaultText.BirthMonth=Месяц
+WebInterface.DefaultText.BirthYear=Год
+WebInterface.DefaultText.FieldName=Название поля
+WebInterface.DefaultText.Option.InsertionDelay=Время ожидания после изменения SOne до того, как выгружать его (в секундах)
+WebInterface.DefaultText.Search=Что вы ищете?
+WebInterface.DefaultText.CreateAlbum.Name=Название альбома
+WebInterface.DefaultText.CreateAlbum.Description=Описание альбома
+WebInterface.DefaultText.EditAlbum.Title=Название альбома
+WebInterface.DefaultText.EditAlbum.Description=Описание альбома
+WebInterface.DefaultText.UploadImage.Title=Название изображения
+WebInterface.DefaultText.UploadImage.Description=Описание изображения
+WebInterface.DefaultText.EditImage.Title=Название изображения
+WebInterface.DefaultText.EditImage.Description=Описание изображения
+WebInterface.DefaultText.Option.PostsPerPage=Количество сообщений, показываемых на странице
+WebInterface.DefaultText.Option.CharactersPerPost=Количество символов, которое должно быть у сообщения, чтобы оно было сокращено
+WebInterface.DefaultText.Option.PostCutOffLength=Количество символов в сокращенном варианте сообщения
+WebInterface.DefaultText.Option.PositiveTrust=Положительное доверие для назначения
+WebInterface.DefaultText.Option.NegativeTrust=Отрицательное доверие для назначения
+WebInterface.DefaultText.Option.TrustComment=Комментарий для установки в web of trust
+WebInterface.Button.Comment=Comment
+WebInterface.Confirmation.DeletePostButton=Да, удалить!
+WebInterface.Confirmation.DeleteReplyButton=Да, удалить!
+WebInterface.SelectBox.Choose=Выбрать…
+WebInterface.SelectBox.Yes=Да
+WebInterface.SelectBox.No=Нет
+WebInterface.ClickToShow.Replies=Нажмите, чтобы показать скрытые ответы.
+WebInterface.VersionInformation.CurrentVersion=Текущая версия:
+WebInterface.VersionInformation.LatestVersion=Последняя версия:
+
+Notification.ClickHereToRead=Нажмите здесь, чтобы прочитать полный текст уведомления.
+Notification.FirstStart.Text=Видимо, вы запустили Sone в первый раз. Чтобы начать, создайте новый Sone из личность web of trust и начните подписываться на другие Sone.
+Notification.Startup.Text=Sone сейчас запускается. Получение всех личностей и Sone из web of trust может занять некоторое время. Если у вас отсутствуют некоторые элементы, пожалуйста, будьте терпеливы. Они скоро появятся.
+Notification.ConfigNotRead.Text=Файл конфигурации "sone.properties" не может быть прочитан, видимо из-за того, что он не был корректно сохранен. Это может произойти в версиях до Sone 0.3.3, и вы ничего не можете с этим сделать.
+Notification.Button.Dismiss=Скрыть
+Notification.NewSone.ShortText=Были обнаружены новые Sone:
+Notification.NewSone.Text=Были обнаружены новые Sone:
+Notification.NewPost.ShortText=Были обнаружены новые сообщения.
+Notification.NewPost.Text=Новые сообщения были обнаружены в следцющих Sone:
+Notification.NewPost.Button.MarkRead=Отметить как прочитанное
+Notification.NewReply.ShortText=Были обнаружены новые ответы.
+Notification.NewReply.Text=Были обнаружены новые ответы на сообщения следующих Sone:
+Notification.SoneIsBeingRescued.Text=Следующие Sone восстанавливаются в данный момент:
+Notification.SoneRescued.Text=Следующие Sone были восстановлены:
+Notification.SoneRescued.Text.RememberToUnlock=Пожалуйста, не забывайте контролировать сообщения и ответы, которые вы дали и не забывайте разблокировать ваши Sone!
+Notification.LockedSones.Text=Следующие Sone были заблокированы более 5 минут. Пожалуйста, проверьте, действительно ли вы хотите держать эти Sone заблокированными:
+Notification.NewVersion.Text=Версия {version} дополнения Sone была найдена. Загрузите ее из USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}​!
+Notification.InsertingImages.Text=Следующие изображения выгружаются:
+Notification.InsertedImages.Text=Следующие изображения были выгружены:
+Notification.ImageInsertFailed.Text=Следующие изображения не могут быть выгружены:
+Notification.Mention.ShortText=Вас упомянули.
+Notification.Mention.Text=Вас упомянули в следующих сообщениях:
+Notification.SoneInsert.Duration={0,number} {0,choice,0#секунд|1#секунда|2#секунды|4<секунд}
index e271246..d9c2fb3 100644 (file)
@@ -67,30 +67,31 @@ function addCommentLink(postId, author, element, insertAfterThisElement) {
        if (($(element).find(".show-reply-form").length > 0) || (getPostElement(element).find(".create-reply").length == 0)) {
                return;
        }
-       commentElement = (function(postId, author) {
+       (function(postId, author, insertAfterThisElement) {
                separator = $("<span> · </span>").addClass("separator");
-               var commentElement = $("<div><span>Comment</span></div>").addClass("show-reply-form").click(function() {
-                       replyElement = $("#sone .post#post-" + postId + " .create-reply");
-                       replyElement.removeClass("hidden");
-                       replyElement.removeClass("light");
-                       (function(replyElement) {
-                               replyElement.find("input.reply-input").blur(function() {
-                                       if ($(this).hasClass("default")) {
-                                               replyElement.addClass("light");
-                                       }
-                               }).focus(function() {
-                                       replyElement.removeClass("light");
-                               });
-                       })(replyElement);
-                       textArea = replyElement.find("input.reply-input").focus().data("textarea");
-                       if (author != getCurrentSoneId()) {
-                               textArea.val(textArea.val() + "@sone://" + author + " ");
-                       }
+               getTranslation("WebInterface.Button.Comment", function(text) {
+                       commentElement = $("<div><span>" + text + "</span></div>").addClass("show-reply-form").click(function() {
+                               replyElement = $("#sone .post#post-" + postId + " .create-reply");
+                               replyElement.removeClass("hidden");
+                               replyElement.removeClass("light");
+                               (function(replyElement) {
+                                       replyElement.find("input.reply-input").blur(function() {
+                                               if ($(this).hasClass("default")) {
+                                                       replyElement.addClass("light");
+                                               }
+                                       }).focus(function() {
+                                               replyElement.removeClass("light");
+                                       });
+                               })(replyElement);
+                               textArea = replyElement.find("input.reply-input").focus().data("textarea");
+                               if (author != getCurrentSoneId()) {
+                                       textArea.val(textArea.val() + "@sone://" + author + " ");
+                               }
+                       });
+                       $(insertAfterThisElement).after(commentElement.clone(true));
+                       $(insertAfterThisElement).after(separator);
                });
-               return commentElement;
-       })(postId, author);
-       $(insertAfterThisElement).after(commentElement.clone(true));
-       $(insertAfterThisElement).after(separator);
+       })(postId, author, insertAfterThisElement);
 }
 
 var translations = {};
@@ -806,7 +807,7 @@ function ajaxifyPost(postElement) {
                        $(".expand-post-text", getPostElement(this)).toggleClass("hidden");
                        $(".shrink-post-text", getPostElement(this)).toggleClass("hidden");
                        return false;
-               })
+               });
        });
 
        /* ajaxify author/post links */
@@ -846,12 +847,14 @@ function ajaxifyPost(postElement) {
        });
 
        /* mark everything as known on click. */
-       $(postElement).click(function(event) {
-               if ($(event.target).hasClass("click-to-show")) {
-                       return false;
-               }
-               markPostAsKnown(this);
-       });
+       (function(postElement) {
+               $(postElement).click(function(event) {
+                       if ($(event.target).hasClass("click-to-show")) {
+                               return false;
+                       }
+                       markPostAsKnown(postElement, false);
+               });
+       })(postElement);
 
        /* hide reply input field. */
        $(postElement).find(".create-reply").addClass("hidden");
@@ -874,7 +877,7 @@ function ajaxifyPost(postElement) {
                }
        });
        (function(postElement) {
-               var soneId = $(".sone-menu-id", postElement).text();
+               var soneId = $(".sone-menu-id:first", postElement).text();
                $(".sone-post-menu .follow", postElement).click(function() {
                        var followElement = this;
                        ajaxGet("followSone.ajax", { "sone": soneId, "formPassword": getFormPassword() }, function() {
@@ -1062,7 +1065,7 @@ function ajaxifyNotification(notification) {
        }
        notification.find("form.mark-as-read button").click(function() {
                allIds = $(":input[name=id]", this.form).val().split(" ");
-               for (index = 0; index < allIds.length; index += 16) {
+               for (var index = 0; index < allIds.length; index += 16) {
                        ids = allIds.slice(index, index + 16).join(" ");
                        ajaxGet("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": $(":input[name=type]", this.form).val(), "id": ids});
                }
@@ -1535,7 +1538,7 @@ function markPostAsKnown(postElements, skipRequest) {
                }
                $(".click-to-show", postElement).removeClass("new");
        });
-       markReplyAsKnown($(postElements).find(".reply"));
+       markReplyAsKnown($(postElements).find(".reply"), true);
 }
 
 function markReplyAsKnown(replyElements, skipRequest) {
@@ -1923,8 +1926,10 @@ $(document).ready(function() {
        getTranslation("WebInterface.Confirmation.DeletePostButton", function(text) {
                getTranslation("WebInterface.Confirmation.DeleteReplyButton", function(text) {
                        getTranslation("WebInterface.DefaultText.Reply", function(text) {
-                               $("#sone .post").each(function() {
-                                       ajaxifyPost(this);
+                               getTranslation("WebInterface.Button.Comment", function(text) {
+                                       $("#sone .post").each(function() {
+                                               ajaxifyPost(this);
+                                       });
                                });
                        });
                });
index e04f4f2..7648c43 100644 (file)
@@ -11,7 +11,7 @@
        <h2><%= Page.About.Homepage.Title|l10n|html></h2>
 
        <p>
-               <%= Page.About.Homepage.Description|l10n|html|replace needle="{link}" replacement='<a href="/USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/33/">'|replace needle="{/link}" replacement='</a>'>
+               <%= Page.About.Homepage.Description|l10n|html|replace needle="{link}" replacement='<a href="/USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/49/">'|replace needle="{/link}" replacement='</a>'>
        </p>
 
        <h2><%= Page.About.License.Title|l10n|html></h2>
index 847e61d..cc6023f 100644 (file)
@@ -1,6 +1,6 @@
 <%include include/head.html>
 
-       <h1><%= Page.DeleteSone.Page.Title|l10n|replace needle="{zone}" replacementKey=currentSone.name|html></h1>
+       <h1><%= Page.DeleteSone.Page.Title|l10n|replace needle="{sone}" replacementKey=currentSone.name|html></h1>
 
        <p><%= Page.DeleteSone.Page.Description|l10n|html></p>
 
diff --git a/src/main/resources/templates/new.html b/src/main/resources/templates/new.html
new file mode 100644 (file)
index 0000000..8e9adf6
--- /dev/null
@@ -0,0 +1,20 @@
+<%include include/head.html>
+
+       <div class="page-id hidden">new</div>
+
+       <h1><%= Page.New.Page.Title|l10n|html></h1>
+
+       <%include include/updateStatus.html>
+
+       <div id="posts">
+               <%= page|store key=pageParameter>
+               <%include include/pagination.html paginationName==pagination-index>
+               <%foreach pagination.items post>
+                       <%include include/viewPost.html>
+               <%foreachelse>
+                       <div><%= Page.New.NothingNew|l10n|html></div>
+               <%/foreach>
+               <%include include/pagination.html>
+       </div>
+
+<%include include/tail.html>
index 1d87e46..6dd3912 100644 (file)
@@ -7,7 +7,10 @@
 
                <h1><%= Page.ViewSone.Page.TitleWithoutSone|l10n|html></h1>
 
-               <p><%= Page.ViewSone.NoSone.Description|l10n|replace needle="{sone}" replacementKey=soneId|html></p>
+               <p>
+                       <%= Page.ViewSone.NoSone.Description|l10n|replace needle="{sone}" replacementKey=soneId|html>
+                       <a href="/WebOfTrust/ShowIdentity?id=<% sone.id|html>"><%= Page.ViewSone.Profile.Name.WoTLink|l10n|html></a>
+               </p>
 
        <%elseifnull sone.name>