Edit blogs, and add blog icons and banners (#460)

Also adds a parameter to `md_to_html` to only render inline elements (so that we don't have titles or images in blog descriptions). And moves the delete button for the blog on the edition page.

I still have to update the SQLite migration once others PRs with migrations will be merged.

Also, there will be a problem when you edit a blog while not owning its banner or icon: when validating they will be reset to their default values… I don't see a good solution to this until we have a better way to handle uploads with Rocket (the same is probably happening for articles btw).

And the icon/banner are not federated yet, I don't know if I should add it to this PR or if it can come after?

![image](https://user-images.githubusercontent.com/16254623/53894510-7d853300-4030-11e9-8a2c-f5c0b0c7f512.png)
![image](https://user-images.githubusercontent.com/16254623/53894539-8b3ab880-4030-11e9-8113-685a27be8d7c.png)

Fixes #453
Fixes #454
This commit is contained in:
Baptiste Gelez 2019-03-22 19:51:36 +01:00 committed by GitHub
parent 6cd9c8a01a
commit bdfad844d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 1391 additions and 456 deletions

View file

@ -0,0 +1,4 @@
-- This file should undo anything in `up.sql`
ALTER TABLE blogs DROP COLUMN summary_html;
ALTER TABLE blogs DROP COLUMN icon_id;
ALTER TABLE blogs DROP COLUMN banner_id;

View file

@ -0,0 +1,4 @@
-- Your SQL goes here
ALTER TABLE blogs ADD COLUMN summary_html TEXT NOT NULL DEFAULT '';
ALTER TABLE blogs ADD COLUMN icon_id INTEGER REFERENCES medias(id) ON DELETE SET NULL DEFAULT NULL;
ALTER TABLE blogs ADD COLUMN banner_id INTEGER REFERENCES medias(id) ON DELETE SET NULL DEFAULT NULL;

View file

@ -0,0 +1,33 @@
-- This file should undo anything in `up.sql
CREATE TABLE blogs2 (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
actor_id VARCHAR NOT NULL,
title VARCHAR NOT NULL,
summary TEXT NOT NULL DEFAULT '',
outbox_url VARCHAR NOT NULL UNIQUE,
inbox_url VARCHAR NOT NULL UNIQUE,
instance_id INTEGER REFERENCES instances(id) ON DELETE CASCADE NOT NULL,
creation_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
ap_url text not null default '' UNIQUE,
private_key TEXT,
public_key TEXT NOT NULL DEFAULT '',
fqn TEXT NOT NULL DEFAULT '',
CONSTRAINT blog_unique UNIQUE (actor_id, instance_id)
);
INSERT INTO blogs2 SELECT
id,
actor_id,
title,
summary,
outbox_url,
inbox_url,
instance_id,
creation_date,
ap_url,
private_key,
public_key,
fqn
FROM blogs;
DROP TABLE blogs;
ALTER TABLE blogs2 RENAME TO blogs;

View file

@ -0,0 +1,4 @@
-- Your SQL goes here
ALTER TABLE blogs ADD COLUMN summary_html TEXT NOT NULL DEFAULT '';
ALTER TABLE blogs ADD COLUMN icon_id INTEGER REFERENCES medias(id) ON DELETE SET NULL DEFAULT NULL;
ALTER TABLE blogs ADD COLUMN banner_id INTEGER REFERENCES medias(id) ON DELETE SET NULL DEFAULT NULL;

View file

@ -65,7 +65,9 @@ pub fn run<'a>(args: &ArgMatches<'a>, conn: &Connection) {
}
fn init<'a>(args: &ArgMatches<'a>, conn: &Connection) {
let path = args.value_of("path").map(|p| Path::new(p).join("search_index"))
let path = args
.value_of("path")
.map(|p| Path::new(p).join("search_index"))
.unwrap_or_else(|| Path::new(&CONFIG.search_index).to_path_buf());
let force = args.is_present("force");

View file

@ -46,8 +46,22 @@ enum State {
Ready,
}
fn to_inline(tag: Tag) -> Tag {
match tag {
Tag::Header(_) | Tag::Table(_) | Tag::TableHead | Tag::TableRow | Tag::TableCell => {
Tag::Paragraph
}
Tag::Image(url, title) => Tag::Link(url, title),
t => t,
}
}
/// Returns (HTML, mentions, hashtags)
pub fn md_to_html(md: &str, base_url: &str) -> (String, HashSet<String>, HashSet<String>) {
pub fn md_to_html(
md: &str,
base_url: &str,
inline: bool,
) -> (String, HashSet<String>, HashSet<String>) {
let parser = Parser::new_ext(md, Options::all());
let (parser, mentions, hashtags): (Vec<Event>, Vec<String>, Vec<String>) = parser
@ -69,6 +83,26 @@ pub fn md_to_html(md: &str, base_url: &str) -> (String, HashSet<String>, HashSet
Some(res)
})
.flat_map(|v| v.into_iter())
// Ignore headings, images, and tables if inline = true
.scan(vec![], |state: &mut Vec<Tag>, evt| {
if inline {
let new_evt = match evt {
Event::Start(t) => {
let tag = to_inline(t);
state.push(tag.clone());
Event::Start(tag)
}
Event::End(t) => match state.pop() {
Some(other) => Event::End(other),
None => Event::End(t),
},
e => e,
};
Some(new_evt)
} else {
Some(evt)
}
})
.map(|evt| match evt {
Event::Text(txt) => {
let (evts, _, _, _, new_mentions, new_hashtags) = txt.chars().fold(
@ -239,7 +273,7 @@ mod tests {
for (md, mentions) in tests {
assert_eq!(
md_to_html(md, "").1,
md_to_html(md, "", false).1,
mentions
.into_iter()
.map(|s| s.to_string())
@ -264,7 +298,7 @@ mod tests {
for (md, mentions) in tests {
assert_eq!(
md_to_html(md, "").2,
md_to_html(md, "", false).2,
mentions
.into_iter()
.map(|s| s.to_string())
@ -272,4 +306,16 @@ mod tests {
);
}
}
#[test]
fn test_inline() {
assert_eq!(
md_to_html("# Hello", "", false).0,
String::from("<h1>Hello</h1>\n")
);
assert_eq!(
md_to_html("# Hello", "", true).0,
String::from("<p>Hello</p>\n")
);
}
}

View file

@ -1,4 +1,4 @@
use activitypub::{actor::Group, collection::OrderedCollection, CustomObject};
use activitypub::{actor::Group, collection::OrderedCollection, object::Image, CustomObject};
use chrono::NaiveDateTime;
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl, SaveChangesDsl};
use openssl::{
@ -16,10 +16,11 @@ use url::Url;
use webfinger::*;
use instance::*;
use medias::Media;
use plume_common::activity_pub::{
ap_accept_header,
inbox::{Deletable, WithInbox},
sign, ActivityStream, ApSignature, Id, IntoId, PublicKey,
sign, ActivityStream, ApSignature, Id, IntoId, PublicKey, Source,
};
use posts::Post;
use safe_string::SafeString;
@ -31,6 +32,7 @@ use {Connection, Error, Result, CONFIG};
pub type CustomGroup = CustomObject<ApSignature, Group>;
#[derive(Queryable, Identifiable, Clone, AsChangeset)]
#[changeset_options(treat_none_as_null = "true")]
pub struct Blog {
pub id: i32,
pub actor_id: String,
@ -44,6 +46,9 @@ pub struct Blog {
pub private_key: Option<String>,
pub public_key: String,
pub fqn: String,
pub summary_html: SafeString,
pub icon_id: Option<i32>,
pub banner_id: Option<i32>,
}
#[derive(Default, Insertable)]
@ -58,6 +63,9 @@ pub struct NewBlog {
pub ap_url: String,
pub private_key: Option<String>,
pub public_key: String,
pub summary_html: SafeString,
pub icon_id: Option<i32>,
pub banner_id: Option<i32>,
}
const BLOG_PREFIX: &str = "~";
@ -189,6 +197,39 @@ impl Blog {
},
)
})?;
let icon_id = acct
.object
.object_props
.icon_image()
.ok()
.and_then(|icon| {
let owner: String = icon.object_props.attributed_to_link::<Id>().ok()?.into();
Media::save_remote(
conn,
icon.object_props.url_string().ok()?,
&User::from_url(conn, &owner).ok()?,
)
.ok()
})
.map(|m| m.id);
let banner_id = acct
.object
.object_props
.image_image()
.ok()
.and_then(|banner| {
let owner: String = banner.object_props.attributed_to_link::<Id>().ok()?.into();
Media::save_remote(
conn,
banner.object_props.url_string().ok()?,
&User::from_url(conn, &owner).ok()?,
)
.ok()
})
.map(|m| m.id);
Blog::insert(
conn,
NewBlog {
@ -204,11 +245,14 @@ impl Blog {
.public_key_publickey()?
.public_key_pem_string()?,
private_key: None,
banner_id,
icon_id,
summary_html: SafeString::new(&acct.object.object_props.summary_string()?),
},
)
}
pub fn to_activity(&self, _conn: &Connection) -> Result<CustomGroup> {
pub fn to_activity(&self, conn: &Connection) -> Result<CustomGroup> {
let mut blog = Group::default();
blog.ap_actor_props
.set_preferred_username_string(self.actor_id.clone())?;
@ -217,7 +261,47 @@ impl Blog {
.set_outbox_string(self.outbox_url.clone())?;
blog.ap_actor_props
.set_inbox_string(self.inbox_url.clone())?;
blog.object_props.set_summary_string(self.summary.clone())?;
blog.object_props
.set_summary_string(self.summary_html.to_string())?;
blog.ap_object_props.set_source_object(Source {
content: self.summary.clone(),
media_type: String::from("text/markdown"),
})?;
let mut icon = Image::default();
icon.object_props.set_url_string(
self.icon_id
.and_then(|id| Media::get(conn, id).and_then(|m| m.url(conn)).ok())
.unwrap_or_default(),
)?;
icon.object_props.set_attributed_to_link(
self.icon_id
.and_then(|id| {
Media::get(conn, id)
.and_then(|m| Ok(User::get(conn, m.owner_id)?.into_id()))
.ok()
})
.unwrap_or_else(|| Id::new(String::new())),
)?;
blog.object_props.set_icon_object(icon)?;
let mut banner = Image::default();
banner.object_props.set_url_string(
self.banner_id
.and_then(|id| Media::get(conn, id).and_then(|m| m.url(conn)).ok())
.unwrap_or_default(),
)?;
banner.object_props.set_attributed_to_link(
self.banner_id
.and_then(|id| {
Media::get(conn, id)
.and_then(|m| Ok(User::get(conn, m.owner_id)?.into_id()))
.ok()
})
.unwrap_or_else(|| Id::new(String::new())),
)?;
blog.object_props.set_image_object(banner)?;
blog.object_props.set_id_string(self.ap_url.clone())?;
let mut public_key = PublicKey::default();
@ -296,6 +380,18 @@ impl Blog {
})
}
pub fn icon_url(&self, conn: &Connection) -> String {
self.icon_id
.and_then(|id| Media::get(conn, id).and_then(|m| m.url(conn)).ok())
.unwrap_or_else(|| "/static/default-avatar.png".to_string())
}
pub fn banner_url(&self, conn: &Connection) -> Option<String> {
self.banner_id
.and_then(|i| Media::get(conn, i).ok())
.and_then(|c| c.url(conn).ok())
}
pub fn delete(&self, conn: &Connection, searcher: &Searcher) -> Result<()> {
for post in Post::get_for_blog(conn, &self)? {
post.delete(&(conn, searcher))?;

View file

@ -106,6 +106,7 @@ impl Comment {
let (html, mentions, _hashtags) = utils::md_to_html(
self.content.get().as_ref(),
&Instance::get_local(conn)?.public_domain,
true,
);
let author = User::get(conn, self.author_id)?;

View file

@ -1,9 +1,9 @@
use std::env::{self, var};
use rocket::Config as RocketConfig;
use rocket::config::Limits;
use rocket::Config as RocketConfig;
use std::env::{self, var};
#[cfg(not(test))]
const DB_NAME: &str = "plume";
const DB_NAME: &str = "plume";
#[cfg(test)]
const DB_NAME: &str = "plume_tests";
@ -16,7 +16,7 @@ pub struct Config {
pub logo: LogoConfig,
}
#[derive(Debug,Clone)]
#[derive(Debug, Clone)]
pub enum RocketError {
InvalidEnv,
InvalidAddress,
@ -27,18 +27,31 @@ fn get_rocket_config() -> Result<RocketConfig, RocketError> {
let mut c = RocketConfig::active().map_err(|_| RocketError::InvalidEnv)?;
let address = var("ROCKET_ADDRESS").unwrap_or_else(|_| "localhost".to_owned());
let port = var("ROCKET_PORT").ok().map(|s| s.parse::<u16>().unwrap()).unwrap_or(7878);
let port = var("ROCKET_PORT")
.ok()
.map(|s| s.parse::<u16>().unwrap())
.unwrap_or(7878);
let secret_key = var("ROCKET_SECRET_KEY").map_err(|_| RocketError::InvalidSecretKey)?;
let form_size = var("FORM_SIZE").unwrap_or_else(|_| "32".to_owned()).parse::<u64>().unwrap();
let activity_size = var("ACTIVITY_SIZE").unwrap_or_else(|_| "1024".to_owned()).parse::<u64>().unwrap();
let form_size = var("FORM_SIZE")
.unwrap_or_else(|_| "32".to_owned())
.parse::<u64>()
.unwrap();
let activity_size = var("ACTIVITY_SIZE")
.unwrap_or_else(|_| "1024".to_owned())
.parse::<u64>()
.unwrap();
c.set_address(address).map_err(|_| RocketError::InvalidAddress)?;
c.set_address(address)
.map_err(|_| RocketError::InvalidAddress)?;
c.set_port(port);
c.set_secret_key(secret_key).map_err(|_| RocketError::InvalidSecretKey) ?;
c.set_secret_key(secret_key)
.map_err(|_| RocketError::InvalidSecretKey)?;
c.set_limits(Limits::new()
.limit("forms", form_size * 1024)
.limit("json", activity_size * 1024));
c.set_limits(
Limits::new()
.limit("forms", form_size * 1024)
.limit("json", activity_size * 1024),
);
Ok(c)
}
@ -168,20 +181,15 @@ impl Default for LogoConfig {
lazy_static! {
pub static ref CONFIG: Config = Config {
base_url: var("BASE_URL").unwrap_or_else(|_| format!(
"127.0.0.1:{}",
var("ROCKET_PORT").unwrap_or_else(|_| "8000".to_owned()
))),
"127.0.0.1:{}",
var("ROCKET_PORT").unwrap_or_else(|_| "8000".to_owned())
)),
db_name: DB_NAME,
#[cfg(feature = "postgres")]
database_url: var("DATABASE_URL").unwrap_or_else(|_| format!(
"postgres://plume:plume@localhost/{}",
DB_NAME
)),
database_url: var("DATABASE_URL")
.unwrap_or_else(|_| format!("postgres://plume:plume@localhost/{}", DB_NAME)),
#[cfg(feature = "sqlite")]
database_url: var("DATABASE_URL").unwrap_or_else(|_| format!(
"{}.sqlite",
DB_NAME
)),
database_url: var("DATABASE_URL").unwrap_or_else(|_| format!("{}.sqlite", DB_NAME)),
search_index: var("SEARCH_INDEX").unwrap_or_else(|_| "search_index".to_owned()),
rocket: get_rocket_config(),
logo: LogoConfig::default(),

View file

@ -34,14 +34,16 @@ pub struct NewFollow {
}
impl Follow {
insert!(follows, NewFollow, |inserted, conn| {
if inserted.ap_url.is_empty() {
insert!(
follows,
NewFollow,
|inserted, conn| if inserted.ap_url.is_empty() {
inserted.ap_url = ap_url(&format!("{}/follows/{}", CONFIG.base_url, inserted.id));
inserted.save_changes(conn).map_err(Error::from)
} else {
Ok(inserted)
}
});
);
get!(follows);
find_by!(follows, find_by_ap_url, ap_url as &str);
@ -88,7 +90,11 @@ impl Follow {
)?;
let mut accept = Accept::default();
let accept_id = ap_url(&format!("{}/follow/{}/accept", CONFIG.base_url.as_str(), &res.id));
let accept_id = ap_url(&format!(
"{}/follow/{}/accept",
CONFIG.base_url.as_str(),
&res.id
));
accept.object_props.set_id_string(accept_id)?;
accept.object_props.set_to_link(from.clone().into_id())?;
accept.object_props.set_cc_link_vec::<Id>(vec![])?;

View file

@ -128,8 +128,8 @@ impl Instance {
short_description: SafeString,
long_description: SafeString,
) -> Result<()> {
let (sd, _, _) = md_to_html(short_description.as_ref(), &self.public_domain);
let (ld, _, _) = md_to_html(long_description.as_ref(), &self.public_domain);
let (sd, _, _) = md_to_html(short_description.as_ref(), &self.public_domain, true);
let (ld, _, _) = md_to_html(long_description.as_ref(), &self.public_domain, false);
diesel::update(self)
.set((
instances::name.eq(name),

View file

@ -235,9 +235,9 @@ macro_rules! get {
/// ```
macro_rules! insert {
($table:ident, $from:ident) => {
insert!($table, $from, |x, _conn| { Ok(x) });
insert!($table, $from, |x, _conn| Ok(x));
};
($table:ident, $from:ident, |$val:ident, $conn:ident | $after:block) => {
($table:ident, $from:ident, |$val:ident, $conn:ident | $( $after:tt )+) => {
last!($table);
pub fn insert(conn: &crate::Connection, new: $from) -> Result<Self> {
@ -247,7 +247,7 @@ macro_rules! insert {
#[allow(unused_mut)]
let mut $val = Self::last(conn)?;
let $conn = conn;
$after
$( $after )+
}
};
}
@ -310,8 +310,8 @@ mod tests {
}
pub fn db() -> Conn {
let conn =
Conn::establish(CONFIG.database_url.as_str()).expect("Couldn't connect to the database");
let conn = Conn::establish(CONFIG.database_url.as_str())
.expect("Couldn't connect to the database");
embedded_migrations::run(&conn).expect("Couldn't run migrations");
#[cfg(feature = "sqlite")]
sql_query("PRAGMA foreign_keys = on;")

View file

@ -210,6 +210,7 @@ impl<'a> Provider<(&'a Connection, &'a Worker, &'a Searcher, Option<i32>)> for P
let (content, mentions, hashtags) = md_to_html(
query.source.clone().unwrap_or_default().clone().as_ref(),
domain,
false,
);
let author = User::get(
@ -756,7 +757,7 @@ impl Post {
post.license = license;
}
let mut txt_hashtags = md_to_html(&post.source, "")
let mut txt_hashtags = md_to_html(&post.source, "", false)
.2
.into_iter()
.map(|s| s.to_camel_case())
@ -994,7 +995,7 @@ impl<'a> FromActivity<LicensedArticle, (&'a Connection, &'a Searcher)> for Post
}
// save mentions and tags
let mut hashtags = md_to_html(&post.source, "")
let mut hashtags = md_to_html(&post.source, "", false)
.2
.into_iter()
.map(|s| s.to_camel_case())

View file

@ -44,6 +44,9 @@ table! {
private_key -> Nullable<Text>,
public_key -> Text,
fqn -> Text,
summary_html -> Text,
icon_id -> Nullable<Int4>,
banner_id -> Nullable<Int4>,
}
}

View file

@ -209,7 +209,7 @@ impl User {
.set((
users::display_name.eq(name),
users::email.eq(email),
users::summary_html.eq(utils::md_to_html(&summary, "").0),
users::summary_html.eq(utils::md_to_html(&summary, "", false).0),
users::summary.eq(summary),
))
.execute(conn)?;
@ -683,7 +683,8 @@ impl User {
.set_followers_string(self.followers_endpoint.clone())?;
let mut endpoints = Endpoint::default();
endpoints.set_shared_inbox_string(ap_url(&format!("{}/inbox/", CONFIG.base_url.as_str())))?;
endpoints
.set_shared_inbox_string(ap_url(&format!("{}/inbox/", CONFIG.base_url.as_str())))?;
actor.ap_actor_props.set_endpoints_endpoint(endpoints)?;
let mut public_key = PublicKey::default();
@ -867,7 +868,7 @@ impl NewUser {
display_name,
is_admin,
summary: summary.to_owned(),
summary_html: SafeString::new(&utils::md_to_html(&summary, "").0),
summary_html: SafeString::new(&utils::md_to_html(&summary, "", false).0),
email: Some(email),
hashed_password: Some(password),
instance_id: Instance::get_local(conn)?.id,

View file

@ -14,7 +14,8 @@ embed_migrations!("../migrations/sqlite");
embed_migrations!("../migrations/postgres");
fn db() -> Conn {
let conn = Conn::establish(CONFIG.database_url.as_str()).expect("Couldn't connect to the database");
let conn =
Conn::establish(CONFIG.database_url.as_str()).expect("Couldn't connect to the database");
embedded_migrations::run(&conn).expect("Couldn't run migrations");
conn
}

View file

@ -45,6 +45,18 @@ msgstr "يجب عليك تسجيل الدخول قصد انشاء مدونة ج
msgid "You are not allowed to delete this blog."
msgstr "لست مِن محرري هذه المدونة."
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "لست مِن محرري هذه المدونة."
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "لست مِن محرري هذه المدونة."
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "لست مِن محرري هذه المدونة."
msgid "You need to be logged in order to like a post"
msgstr "يجب عليك تسجيل الدخول قصد الإعجاب بالمنشور"
@ -388,6 +400,13 @@ msgstr "يستضيف <em>{0}</em> مستخدمين"
msgid "Read the detailed rules"
msgstr "إقرأ القواعد بالتفصيل"
msgid "None"
msgstr "لا شيء"
#, fuzzy
msgid "No description"
msgstr "الوصف الطويل"
msgid "View all"
msgstr "عرضها كافة"
@ -561,9 +580,6 @@ msgstr ""
msgid "Illustration"
msgstr "الصورة الإيضاحية"
msgid "None"
msgstr "لا شيء"
msgid "This is a draft, don't publish it yet."
msgstr "هذه مُسودّة، لا تقم بنشرها الآن."
@ -682,6 +698,39 @@ msgstr "حصل خطأ ما مِن جهتنا."
msgid "Sorry about that. If you think this is a bug, please report it."
msgstr "نعتذر عن الإزعاج. إن كنت تضن أن هذه مشكلة، يرجى إبلاغنا."
#, fuzzy
msgid "Edit \"{}\""
msgstr "تعديل {0}"
msgid "Description"
msgstr "الوصف"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "Upload images"
msgstr "إرسال"
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "انشاء مدونة"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr "نوخى الحذر هنا، فكل إجراء تأخذه هنا لا يمكن الغاؤه."
#, fuzzy
msgid "Permanently delete this blog"
msgstr "احذف هذه المدونة"
#, fuzzy
msgid "New Blog"
msgstr "مدونة جديدة"
@ -692,6 +741,12 @@ msgstr "انشئ مدونة"
msgid "Create blog"
msgstr "انشاء مدونة"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "مقال جديد"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
@ -702,30 +757,9 @@ msgstr[3] "{0} مؤلف على هذه المدونة: "
msgstr[4] "{0} مؤلفون على هذه المدونة: "
msgstr[5] "{0} كُتاب على هذه المدونة: "
#, fuzzy
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "لا مقال على هذه المدونة"
msgstr[1] "{0} مقال على هذه المدونة"
msgstr[2] "مقالَين على هذه المدونة"
msgstr[3] "{0} مقالات على هذه المدونة"
msgstr[4] "{0} مقالات على هذه المدونة"
msgstr[5] "{0} مقالات على هذه المدونة"
msgid "No posts to see here yet."
msgstr "في الوقت الراهن لا توجد أية منشورات هنا."
msgid "New article"
msgstr "مقال جديد"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr "نوخى الحذر هنا، فكل إجراء تأخذه هنا لا يمكن الغاؤه."
#, fuzzy
msgid "Permanently delete this blog"
msgstr "احذف هذه المدونة"
msgid "Articles tagged \"{0}\""
msgstr "المقالات الموسومة بـ \"{0}\""
@ -753,9 +787,6 @@ msgstr "تفاصيل الصورة"
msgid "Media upload"
msgstr "إرسال الوسائط"
msgid "Description"
msgstr "الوصف"
#, fuzzy
msgid "Useful for visually impaired people, as well as licensing information"
msgstr "صالح للمُعاقين بصريا وكذا لمعلومات الرخصة"
@ -787,6 +818,16 @@ msgstr "قم بنسخه و إلصاقه في محتوى مقالك لعرض ال
msgid "Use as avatar"
msgstr "استخدمها كصورة رمزية"
#, fuzzy
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "لا مقال على هذه المدونة"
#~ msgstr[1] "{0} مقال على هذه المدونة"
#~ msgstr[2] "مقالَين على هذه المدونة"
#~ msgstr[3] "{0} مقالات على هذه المدونة"
#~ msgstr[4] "{0} مقالات على هذه المدونة"
#~ msgstr[5] "{0} مقالات على هذه المدونة"
#~ msgid "{0}'s followers"
#~ msgstr "{0} متابِعون"

View file

@ -44,6 +44,18 @@ msgstr "Du musst eingeloggt sein, um einen neuen Beitrag zu schreiben"
msgid "You are not allowed to delete this blog."
msgstr "Du bist kein Autor in diesem Blog."
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "Du bist kein Autor in diesem Blog."
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "Du bist kein Autor in diesem Blog."
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "Du bist kein Autor in diesem Blog."
#, fuzzy
msgid "You need to be logged in order to like a post"
msgstr "Du musst eingeloggt sein, um einen Beitrag zu Liken"
@ -409,6 +421,13 @@ msgstr ""
msgid "Read the detailed rules"
msgstr "Lies die detailierten Regeln"
msgid "None"
msgstr ""
#, fuzzy
msgid "No description"
msgstr "Lange Beschreibung"
msgid "View all"
msgstr "Alles anzeigen"
@ -576,9 +595,6 @@ msgstr ""
msgid "Illustration"
msgstr "Administration"
msgid "None"
msgstr ""
#, fuzzy
msgid "This is a draft, don't publish it yet."
msgstr "Dieser Beitrag ist noch nicht veröffentlicht."
@ -705,33 +721,30 @@ msgstr ""
"gerne melden."
#, fuzzy
msgid "New Blog"
msgstr "Neuer Blog"
msgid "Edit \"{}\""
msgstr "Bearbeiten"
msgid "Create a blog"
msgstr "Erstelle einen Blog"
msgid "Description"
msgstr "Beschreibung"
msgid "Create blog"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "Upload images"
msgstr "Hochladen"
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "Blog erstellen"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Ein Autor in diesem Blog: "
msgstr[1] "{0} Autoren in diesem Blog: "
#, fuzzy
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "Ein Artikel in diesem Blog"
msgstr[1] "{0} Artikel in diesem Blog"
msgid "No posts to see here yet."
msgstr "Bisher keine Artikel vorhanden."
msgid "New article"
msgstr "Neuer Artikel"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
@ -741,6 +754,31 @@ msgstr ""
msgid "Permanently delete this blog"
msgstr "Artikel löschen"
#, fuzzy
msgid "New Blog"
msgstr "Neuer Blog"
msgid "Create a blog"
msgstr "Erstelle einen Blog"
msgid "Create blog"
msgstr "Blog erstellen"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "Neuer Artikel"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Ein Autor in diesem Blog: "
msgstr[1] "{0} Autoren in diesem Blog: "
msgid "No posts to see here yet."
msgstr "Bisher keine Artikel vorhanden."
#, fuzzy
msgid "Articles tagged \"{0}\""
msgstr "Mit \"{0}\" markierte Artikel"
@ -768,9 +806,6 @@ msgstr ""
msgid "Media upload"
msgstr "Hochladen von Mediendateien"
msgid "Description"
msgstr "Beschreibung"
#, fuzzy
msgid "Useful for visually impaired people, as well as licensing information"
msgstr "Hilfreich für Sehbehinderte und zur Lizenziserung"
@ -804,6 +839,12 @@ msgstr "Um diese Mediendatei einzufügen, kopiere sie in deine Artikel."
msgid "Use as avatar"
msgstr "Als Avatar verwenden"
#, fuzzy
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "Ein Artikel in diesem Blog"
#~ msgstr[1] "{0} Artikel in diesem Blog"
#~ msgid "{0}'s followers"
#~ msgstr "{0}s Follower"

View file

@ -46,6 +46,18 @@ msgstr ""
msgid "You are not allowed to delete this blog."
msgstr ""
# src/routes/blogs.rs:170
msgid "You are not allowed to edit this blog."
msgstr ""
# src/main.rs:1
msgid "You can't use this media as blog icon."
msgstr ""
# src/main.rs:1
msgid "You can't use this media as blog banner."
msgstr ""
# src/routes/likes.rs:41
msgid "You need to be logged in order to like a post"
msgstr ""
@ -383,6 +395,12 @@ msgstr ""
msgid "Read the detailed rules"
msgstr ""
msgid "None"
msgstr ""
msgid "No description"
msgstr ""
msgid "View all"
msgstr ""
@ -550,9 +568,6 @@ msgstr ""
msgid "Illustration"
msgstr ""
msgid "None"
msgstr ""
msgid "This is a draft, don't publish it yet."
msgstr ""
@ -657,6 +672,34 @@ msgstr ""
msgid "Sorry about that. If you think this is a bug, please report it."
msgstr ""
msgid "Edit \"{}\""
msgstr ""
msgid "Description"
msgstr ""
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
msgid "Upload images"
msgstr ""
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
msgid "Update blog"
msgstr ""
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
msgid "Permanently delete this blog"
msgstr ""
msgid "New Blog"
msgstr ""
@ -666,26 +709,18 @@ msgstr ""
msgid "Create blog"
msgstr ""
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] ""
msgstr[1] ""
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] ""
msgstr[1] ""
msgid "No posts to see here yet."
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr ""
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] ""
msgstr[1] ""
msgid "Permanently delete this blog"
msgid "No posts to see here yet."
msgstr ""
msgid "Articles tagged \"{0}\""
@ -712,9 +747,6 @@ msgstr ""
msgid "Media upload"
msgstr ""
msgid "Description"
msgstr ""
msgid "Useful for visually impaired people, as well as licensing information"
msgstr ""

View file

@ -44,6 +44,18 @@ msgstr "Necesitas iniciar sesión para crear un nuevo blog"
msgid "You are not allowed to delete this blog."
msgstr ""
# src/routes/blogs.rs:170
msgid "You are not allowed to edit this blog."
msgstr ""
# src/main.rs:1
msgid "You can't use this media as blog icon."
msgstr ""
# src/main.rs:1
msgid "You can't use this media as blog banner."
msgstr ""
msgid "You need to be logged in order to like a post"
msgstr "Necesitas iniciar sesión para gustar una publicación"
@ -368,6 +380,12 @@ msgstr ""
msgid "Read the detailed rules"
msgstr ""
msgid "None"
msgstr ""
msgid "No description"
msgstr ""
msgid "View all"
msgstr ""
@ -536,9 +554,6 @@ msgstr ""
msgid "Illustration"
msgstr ""
msgid "None"
msgstr ""
msgid "This is a draft, don't publish it yet."
msgstr ""
@ -645,6 +660,35 @@ msgid "Sorry about that. If you think this is a bug, please report it."
msgstr ""
"Disculpe la molestia. Si cree que esto es un defecto, por favor repórtalo."
msgid "Edit \"{}\""
msgstr ""
msgid "Description"
msgstr ""
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
msgid "Upload images"
msgstr ""
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "Crear el blog"
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
msgid "Permanently delete this blog"
msgstr ""
#, fuzzy
msgid "New Blog"
msgstr "Nuevo blog"
@ -655,29 +699,21 @@ msgstr "Crear un blog"
msgid "Create blog"
msgstr "Crear el blog"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "Nueva publicación"
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] ""
msgstr[1] ""
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] ""
msgstr[1] ""
#, fuzzy
msgid "No posts to see here yet."
msgstr "No hay publicaciones para ver aquí ahora."
msgid "New article"
msgstr "Nueva publicación"
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
msgid "Permanently delete this blog"
msgstr ""
msgid "Articles tagged \"{0}\""
msgstr ""
@ -702,9 +738,6 @@ msgstr ""
msgid "Media upload"
msgstr ""
msgid "Description"
msgstr ""
msgid "Useful for visually impaired people, as well as licensing information"
msgstr ""

View file

@ -47,6 +47,18 @@ msgstr "Vous devez vous connecter pour écrire un article"
msgid "You are not allowed to delete this blog."
msgstr "Vous nêtes pas auteur⋅ice dans ce blog."
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "Vous nêtes pas auteur⋅ice dans ce blog."
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "Vous nêtes pas auteur⋅ice dans ce blog."
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "Vous nêtes pas auteur⋅ice dans ce blog."
#, fuzzy
msgid "You need to be logged in order to like a post"
msgstr "Vous devez vous connecter pour aimer un article"
@ -412,6 +424,13 @@ msgstr "Accueille <em>{0} personnes"
msgid "Read the detailed rules"
msgstr "Lire les règles détaillées"
msgid "None"
msgstr ""
#, fuzzy
msgid "No description"
msgstr "Description longue"
msgid "View all"
msgstr "Tout afficher"
@ -572,9 +591,6 @@ msgstr "Laisser vide sil ny en a pas"
msgid "Illustration"
msgstr "Administration"
msgid "None"
msgstr ""
#, fuzzy
msgid "This is a draft, don't publish it yet."
msgstr "Cet article nest pas encore publié."
@ -699,33 +715,31 @@ msgstr ""
"signaler."
#, fuzzy
msgid "New Blog"
msgstr "Nouveau blog"
msgid "Edit \"{}\""
msgstr "Modifier {0}"
msgid "Create a blog"
msgstr "Créer un blog"
msgid "Description"
msgstr "Description"
msgid "Create blog"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "Upload images"
msgstr "Téléverser"
#, fuzzy
msgid "Blog icon"
msgstr "Nom du blog"
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "Créer le blog"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "{0} auteur⋅ice dans ce blog : "
msgstr[1] "{0} auteur⋅ice⋅s dans ce blog : "
#, fuzzy
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "{0} article dans ce blog"
msgstr[1] "{0} articles dans ce blog"
msgid "No posts to see here yet."
msgstr "Aucun article pour le moment."
msgid "New article"
msgstr "Nouvel article"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
@ -735,6 +749,31 @@ msgstr ""
msgid "Permanently delete this blog"
msgstr "Supprimer ce blog"
#, fuzzy
msgid "New Blog"
msgstr "Nouveau blog"
msgid "Create a blog"
msgstr "Créer un blog"
msgid "Create blog"
msgstr "Créer le blog"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "Nouvel article"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "{0} auteur⋅ice dans ce blog : "
msgstr[1] "{0} auteur⋅ice⋅s dans ce blog : "
msgid "No posts to see here yet."
msgstr "Aucun article pour le moment."
#, fuzzy
msgid "Articles tagged \"{0}\""
msgstr "Articles taggués « {0} »"
@ -763,9 +802,6 @@ msgstr ""
msgid "Media upload"
msgstr "Téléversement de média"
msgid "Description"
msgstr "Description"
#, fuzzy
msgid "Useful for visually impaired people, as well as licensing information"
msgstr "Utile pour les personnes malvoyantes et les informations de copyright."
@ -799,6 +835,12 @@ msgstr "Copiez-le dans vos articles pour insérer ce média."
msgid "Use as avatar"
msgstr "Utiliser comme avatar"
#, fuzzy
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "{0} article dans ce blog"
#~ msgstr[1] "{0} articles dans ce blog"
#~ msgid "{0}'s followers"
#~ msgstr "Abonné⋅e⋅s de {0}"

View file

@ -43,6 +43,18 @@ msgstr "Debe estar conectada para escribir un novo artigo"
msgid "You are not allowed to delete this blog."
msgstr "Vostede non é autora en este blog."
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "Vostede non é autora en este blog."
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "Vostede non é autora en este blog."
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "Vostede non é autora en este blog."
#, fuzzy
msgid "You need to be logged in order to like a post"
msgstr "Debe estar conectada para gustar unha entrada"
@ -405,6 +417,13 @@ msgstr ""
msgid "Read the detailed rules"
msgstr "Lea o detalle das normas"
msgid "None"
msgstr ""
#, fuzzy
msgid "No description"
msgstr "Descrición longa"
msgid "View all"
msgstr "Ver todos"
@ -572,9 +591,6 @@ msgstr "Deixar baldeiro si non hai ningunha"
msgid "Illustration"
msgstr "Administración"
msgid "None"
msgstr ""
msgid "This is a draft, don't publish it yet."
msgstr "Esto é un borrador, non publicar por agora."
@ -696,6 +712,39 @@ msgstr "Algo fallou pola nosa parte"
msgid "Sorry about that. If you think this is a bug, please report it."
msgstr "Lamentálmolo. Si cree que é un bug, infórmenos por favor."
#, fuzzy
msgid "Edit \"{}\""
msgstr "Editar"
msgid "Description"
msgstr "Descrición"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "Upload images"
msgstr "Subir"
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "Crear blog"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr "Sexa coidadosa, as accións tomadas non se poden restablecer."
#, fuzzy
msgid "Permanently delete this blog"
msgstr "Borrar este blog"
#, fuzzy
msgid "New Blog"
msgstr "Novo blog"
@ -706,32 +755,21 @@ msgstr "Crear un blog"
msgid "Create blog"
msgstr "Crear blog"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "Novo artigo"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Unha autora en este blog: "
msgstr[1] "{0} autoras en este blog: "
#, fuzzy
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "Un artigo en este blog"
msgstr[1] "{0} artigos en este blog"
msgid "No posts to see here yet."
msgstr "Aínda non hai entradas publicadas"
msgid "New article"
msgstr "Novo artigo"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr "Sexa coidadosa, as accións tomadas non se poden restablecer."
#, fuzzy
msgid "Permanently delete this blog"
msgstr "Borrar este blog"
#, fuzzy
msgid "Articles tagged \"{0}\""
msgstr "Artigos etiquetados con {0}"
@ -759,9 +797,6 @@ msgstr ""
msgid "Media upload"
msgstr "Subir medios"
msgid "Description"
msgstr "Descrición"
#, fuzzy
msgid "Useful for visually impaired people, as well as licensing information"
msgstr "Útil para xente con problemas visuais e licenzas"
@ -795,6 +830,12 @@ msgstr "Copie para incrustar este contido nos seus artigos"
msgid "Use as avatar"
msgstr "Utilizar como avatar"
#, fuzzy
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "Un artigo en este blog"
#~ msgstr[1] "{0} artigos en este blog"
#, fuzzy
#~ msgid "{0}'s followers"
#~ msgstr "Unha seguidora"

View file

@ -43,6 +43,18 @@ msgstr "Devi effettuare l'accesso per scrivere un post"
msgid "You are not allowed to delete this blog."
msgstr "Non sei l'autore di questo blog."
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "Non sei l'autore di questo blog."
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "Non sei l'autore di questo blog."
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "Non sei l'autore di questo blog."
#, fuzzy
msgid "You need to be logged in order to like a post"
msgstr "Devi effettuare l'accesso per mettere mi piace ad un post"
@ -408,6 +420,13 @@ msgstr ""
msgid "Read the detailed rules"
msgstr "Leggi le regole dettagliate"
msgid "None"
msgstr ""
#, fuzzy
msgid "No description"
msgstr "Descrizione lunga"
msgid "View all"
msgstr "Vedi tutto"
@ -575,9 +594,6 @@ msgstr "Lascialo vuoto se non è presente nessuno"
msgid "Illustration"
msgstr "Amministrazione"
msgid "None"
msgstr ""
msgid "This is a draft, don't publish it yet."
msgstr "Questa è una bozza, non pubblicarla ancora."
@ -702,33 +718,30 @@ msgid "Sorry about that. If you think this is a bug, please report it."
msgstr "Scusa per questo. Se pensi sia un bug, per favore segnalacelo."
#, fuzzy
msgid "New Blog"
msgstr "Nuovo blog"
msgid "Edit \"{}\""
msgstr "Modifica"
msgid "Create a blog"
msgstr "Crea un blog"
msgid "Description"
msgstr "Descrizione"
msgid "Create blog"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "Upload images"
msgstr "Carica"
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "Crea blog"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Un autore in questo blog: "
msgstr[1] "{0} autori in questo blog: "
#, fuzzy
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "Un articolo in questo blog"
msgstr[1] "{0} articoli in questo blog"
msgid "No posts to see here yet."
msgstr "Nessun post da mostrare qui."
msgid "New article"
msgstr "Nuovo articolo"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
@ -738,6 +751,31 @@ msgstr ""
msgid "Permanently delete this blog"
msgstr "Elimina questo blog"
#, fuzzy
msgid "New Blog"
msgstr "Nuovo blog"
msgid "Create a blog"
msgstr "Crea un blog"
msgid "Create blog"
msgstr "Crea blog"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "Nuovo articolo"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Un autore in questo blog: "
msgstr[1] "{0} autori in questo blog: "
msgid "No posts to see here yet."
msgstr "Nessun post da mostrare qui."
#, fuzzy
msgid "Articles tagged \"{0}\""
msgstr "Articoli etichettati \"{0}\""
@ -766,9 +804,6 @@ msgstr ""
msgid "Media upload"
msgstr "Caricamento di un media"
msgid "Description"
msgstr "Descrizione"
#, fuzzy
msgid "Useful for visually impaired people, as well as licensing information"
msgstr "Utile per persone ipovedenti e per informazioni sulla licenza"
@ -802,6 +837,12 @@ msgstr "Copialo nei tuoi articoli per inserire questo media."
msgid "Use as avatar"
msgstr "Usa come avatar"
#, fuzzy
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "Un articolo in questo blog"
#~ msgstr[1] "{0} articoli in questo blog"
#, fuzzy
#~ msgid "{0}'s followers"
#~ msgstr "Uno ti segue"

View file

@ -45,6 +45,18 @@ msgstr "新しいブログを作成するにはログインする必要があり
msgid "You are not allowed to delete this blog."
msgstr "あなたはこのブログの作者ではありません。"
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "あなたはこのブログの作者ではありません。"
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "あなたはこのブログの作者ではありません。"
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "あなたはこのブログの作者ではありません。"
msgid "You need to be logged in order to like a post"
msgstr "投稿をいいねするにはログインする必要があります"
@ -237,6 +249,7 @@ msgstr "Plume {{ version }} を実行中"
msgid "Edit your account"
msgstr "自分のアカウントを編集"
#, fuzzy
msgid "Your Profile"
msgstr "自分のプロフィール"
@ -257,6 +270,7 @@ msgstr "メールアドレス"
msgid "Summary"
msgstr "要約"
#, fuzzy
msgid "Update account"
msgstr "アカウントをアップデート"
@ -393,6 +407,13 @@ msgstr ""
msgid "Read the detailed rules"
msgstr "詳細な規則を読む"
msgid "None"
msgstr "なし"
#, fuzzy
msgid "No description"
msgstr "長い説明"
msgid "View all"
msgstr "すべて表示"
@ -566,9 +587,6 @@ msgstr ""
msgid "Illustration"
msgstr "図"
msgid "None"
msgstr "なし"
msgid "This is a draft, don't publish it yet."
msgstr "これは下書きなので、まだ公開しないでください。"
@ -681,6 +699,39 @@ msgid "Sorry about that. If you think this is a bug, please report it."
msgstr ""
"申し訳ありません。これがバグだと思われる場合は、問題を報告してください。"
#, fuzzy
msgid "Edit \"{}\""
msgstr "編集"
msgid "Description"
msgstr "説明"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "Upload images"
msgstr "アップロード"
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "ブログを作成"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr "十分ご注意ください。ここで行ったすべての操作は取り消しできません。"
#, fuzzy
msgid "Permanently delete this blog"
msgstr "このブログを削除"
#, fuzzy
msgid "New Blog"
msgstr "新しいブログ"
@ -691,29 +742,19 @@ msgstr "ブログを作成"
msgid "Create blog"
msgstr "ブログを作成"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "ブログに {0} 人の作成者がいます: "
#, fuzzy
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "ブログに {0} 件の記事があります"
msgid "No posts to see here yet."
msgstr "ここにはまだ表示できる投稿がありません。"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "新しい記事"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr "十分ご注意ください。ここで行ったすべての操作は取り消しできません。"
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "ブログに {0} 人の作成者がいます: "
#, fuzzy
msgid "Permanently delete this blog"
msgstr "このブログを削除"
msgid "No posts to see here yet."
msgstr "ここにはまだ表示できる投稿がありません。"
#, fuzzy
msgid "Articles tagged \"{0}\""
@ -743,9 +784,6 @@ msgstr "メディアの詳細"
msgid "Media upload"
msgstr "メディアのアップロード"
msgid "Description"
msgstr "説明"
#, fuzzy
msgid "Useful for visually impaired people, as well as licensing information"
msgstr "視覚的に障害のある方や認可の際に便利です"
@ -777,6 +815,11 @@ msgstr "このメディアを記事に挿入するには、自分の記事にコ
msgid "Use as avatar"
msgstr "アバターとして使う"
#, fuzzy
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "ブログに {0} 件の記事があります"
#~ msgid "{0}'s followers"
#~ msgstr "{{ count }} フォロワー"

View file

@ -46,6 +46,18 @@ msgstr "Du må være logget inn for å lage en ny blogg"
msgid "You are not allowed to delete this blog."
msgstr "Du er ikke denne bloggens forfatter."
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "Du er ikke denne bloggens forfatter."
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "Du er ikke denne bloggens forfatter."
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "Du er ikke denne bloggens forfatter."
#, fuzzy
msgid "You need to be logged in order to like a post"
msgstr "Du må være logget inn for å like et innlegg"
@ -411,6 +423,13 @@ msgstr ""
msgid "Read the detailed rules"
msgstr "Les reglene"
msgid "None"
msgstr ""
#, fuzzy
msgid "No description"
msgstr "Lang beskrivelse"
msgid "View all"
msgstr ""
@ -600,9 +619,6 @@ msgstr ""
msgid "Illustration"
msgstr "Administrasjon"
msgid "None"
msgstr ""
msgid "This is a draft, don't publish it yet."
msgstr ""
@ -720,6 +736,38 @@ msgstr ""
"Beklager så mye. Dersom du tror dette er en bug, vær grei å rapportér det "
"til oss."
#, fuzzy
msgid "Edit \"{}\""
msgstr "Kommentér \"{0}\""
#, fuzzy
msgid "Description"
msgstr "Lang beskrivelse"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "Upload images"
msgstr "Din kommentar"
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "Opprett blogg"
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
msgid "Permanently delete this blog"
msgstr ""
#, fuzzy
msgid "New Blog"
msgstr "Ny blogg"
@ -730,30 +778,21 @@ msgstr "Lag en ny blogg"
msgid "Create blog"
msgstr "Opprett blogg"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "Ny artikkel"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Én forfatter av denne bloggen: "
msgstr[1] "{0} forfattere av denne bloggen: "
#, fuzzy
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "Én artikkel i denne bloggen"
msgstr[1] "{0} artikler i denne bloggen"
msgid "No posts to see here yet."
msgstr "Ingen innlegg å vise enda."
msgid "New article"
msgstr "Ny artikkel"
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
msgid "Permanently delete this blog"
msgstr ""
#, fuzzy
msgid "Articles tagged \"{0}\""
msgstr "Om {0}"
@ -780,10 +819,6 @@ msgstr ""
msgid "Media upload"
msgstr ""
#, fuzzy
msgid "Description"
msgstr "Lang beskrivelse"
msgid "Useful for visually impaired people, as well as licensing information"
msgstr ""
@ -812,6 +847,12 @@ msgstr ""
msgid "Use as avatar"
msgstr ""
#, fuzzy
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "Én artikkel i denne bloggen"
#~ msgstr[1] "{0} artikler i denne bloggen"
#, fuzzy
#~ msgid "{0}'s followers"
#~ msgstr "Én følger"

View file

@ -39,6 +39,18 @@ msgstr "Musisz się zalogować, aby utworzyć bloga"
msgid "You are not allowed to delete this blog."
msgstr "Nie masz uprawnień do usunięcia tego bloga."
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "Nie masz uprawnień do usunięcia tego bloga."
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "Nie masz uprawnień do usunięcia tego bloga."
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "Nie masz uprawnień do usunięcia tego bloga."
msgid "You need to be logged in order to like a post"
msgstr "Musisz się zalogować, aby polubić wpis"
@ -370,6 +382,13 @@ msgstr "Używana przez <em>{0}</em> użytkowników"
msgid "Read the detailed rules"
msgstr "Przeczytaj szczegółowe zasady"
msgid "None"
msgstr "Brak"
#, fuzzy
msgid "No description"
msgstr "Szczegółowy opis"
msgid "View all"
msgstr "Zobacz wszystko"
@ -539,9 +558,6 @@ msgstr "Pozostawienie pustego jest równe zastrzeżeniu wszystkich praw"
msgid "Illustration"
msgstr "Ilustracja"
msgid "None"
msgstr "Brak"
msgid "This is a draft, don't publish it yet."
msgstr "To jest szkic, nie publikuj go jeszcze."
@ -653,6 +669,38 @@ msgid "Sorry about that. If you think this is a bug, please report it."
msgstr ""
"Przepraszamy. Jeżeli uważasz że wystąpił błąd, prosimy o zgłoszenie go."
#, fuzzy
msgid "Edit \"{}\""
msgstr "Edytuj {0}"
msgid "Description"
msgstr "Opis"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "Upload images"
msgstr "Wyślij"
#, fuzzy
msgid "Blog icon"
msgstr "Tytuł bloga"
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "Utwórz blog"
msgid "Be very careful, any action taken here can't be reversed."
msgstr "Bądź ostrożny(-a), działania podjęte tutaj nie mogą zostać cofnięte."
msgid "Permanently delete this blog"
msgstr "Bezpowrotnie usuń ten blog"
msgid "New Blog"
msgstr "Nowy blog"
@ -662,30 +710,21 @@ msgstr "Utwórz blog"
msgid "Create blog"
msgstr "Utwórz blog"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "Nowy artykuł"
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Ten blog ma jednego autora: "
msgstr[1] "Ten blog ma {0} autorów: "
msgstr[2] "Ten blog ma {0} autorów: "
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "Jeden artykuł na tym blogu"
msgstr[1] "{0} artykuły na tym blogu"
msgstr[2] "{0} artykułów na tym blogu"
msgid "No posts to see here yet."
msgstr "Brak wpisów do wyświetlenia."
msgid "New article"
msgstr "Nowy artykuł"
msgid "Be very careful, any action taken here can't be reversed."
msgstr "Bądź ostrożny(-a), działania podjęte tutaj nie mogą zostać cofnięte."
msgid "Permanently delete this blog"
msgstr "Bezpowrotnie usuń ten blog"
msgid "Articles tagged \"{0}\""
msgstr "Artykuły oznaczone „{0}”"
@ -712,9 +751,6 @@ msgstr "Szczegóły zawartości multimedialnej"
msgid "Media upload"
msgstr "Wysyłanie zawartości multimedialnej"
msgid "Description"
msgstr "Opis"
msgid "Useful for visually impaired people, as well as licensing information"
msgstr ""
"Przydatny dla osób z problemami ze wzrokiem oraz do umieszczenia informacji "
@ -744,6 +780,12 @@ msgstr "Skopiuj do swoich artykułów, aby wstawić tę zawartość multimedialn
msgid "Use as avatar"
msgstr "Użyj jako awataru"
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "Jeden artykuł na tym blogu"
#~ msgstr[1] "{0} artykuły na tym blogu"
#~ msgstr[2] "{0} artykułów na tym blogu"
#~ msgid "{0}'s followers"
#~ msgstr "Obserwujący {0}"

View file

@ -12,95 +12,107 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
# src/template_utils.rs:34
# src/template_utils.rs:68
msgid "{0} commented your article."
msgstr ""
# src/template_utils.rs:35
# src/template_utils.rs:69
msgid "{0} is subscribed to you."
msgstr ""
# src/template_utils.rs:36
# src/template_utils.rs:70
msgid "{0} liked your article."
msgstr ""
# src/template_utils.rs:37
# src/template_utils.rs:71
msgid "{0} mentioned you."
msgstr ""
# src/template_utils.rs:38
# src/template_utils.rs:72
msgid "{0} boosted your article."
msgstr ""
# src/template_utils.rs:68
# src/template_utils.rs:108
msgid "{0}'s avatar"
msgstr ""
# src/routes/blogs.rs:64
# src/routes/blogs.rs:70
msgid "You need to be logged in order to create a new blog"
msgstr ""
# src/routes/blogs.rs:134
# src/routes/blogs.rs:169
msgid "You are not allowed to delete this blog."
msgstr ""
# src/routes/likes.rs:41
# src/routes/blogs.rs:214
msgid "You are not allowed to edit this blog."
msgstr ""
# src/routes/blogs.rs:253
msgid "You can't use this media as blog icon."
msgstr ""
# src/routes/blogs.rs:271
msgid "You can't use this media as blog banner."
msgstr ""
# src/routes/likes.rs:47
msgid "You need to be logged in order to like a post"
msgstr ""
# src/routes/notifications.rs:23
# src/routes/notifications.rs:29
msgid "You need to be logged in order to see your notifications"
msgstr ""
# src/routes/posts.rs:81
# src/routes/posts.rs:92
msgid "This post isn't published yet."
msgstr ""
# src/routes/posts.rs:100
# src/routes/posts.rs:120
msgid "You need to be logged in order to write a new post"
msgstr ""
# src/routes/posts.rs:113
# src/routes/posts.rs:138
msgid "You are not author in this blog."
msgstr ""
# src/routes/posts.rs:119
# src/routes/posts.rs:145
msgid "New post"
msgstr ""
# src/routes/posts.rs:156
# src/routes/posts.rs:190
msgid "Edit {0}"
msgstr ""
# src/routes/reshares.rs:41
# src/routes/reshares.rs:47
msgid "You need to be logged in order to reshare a post"
msgstr ""
# src/routes/session.rs:161
# src/routes/session.rs:181
msgid "Password reset"
msgstr ""
# src/routes/session.rs:162
# src/routes/session.rs:182
msgid "Here is the link to reset your password: {0}"
msgstr ""
# src/routes/session.rs:222
# src/routes/session.rs:259
msgid "Your password was successfully reset."
msgstr ""
# src/routes/session.rs:224
# src/routes/session.rs:263
msgid "Sorry, but the link expired. Try again"
msgstr ""
# src/routes/user.rs:126
# src/routes/user.rs:148
msgid "You need to be logged in order to access your dashboard"
msgstr ""
# src/routes/user.rs:159
# src/routes/user.rs:187
msgid "You need to be logged in order to subscribe to someone"
msgstr ""
# src/routes/user.rs:240
# src/routes/user.rs:287
msgid "You need to be logged in order to edit your profile"
msgstr ""
@ -188,11 +200,11 @@ msgstr ""
msgid "Nothing to see here yet. Try to subscribe to more people."
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Name"
msgstr ""
# src/template_utils.rs:146
# src/template_utils.rs:220
msgid "Optional"
msgstr ""
@ -208,7 +220,7 @@ msgstr ""
msgid "Long description"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Default article license"
msgstr ""
@ -245,15 +257,14 @@ msgstr ""
msgid "Upload an avatar"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Display name"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Email"
msgstr ""
# src/template_utils.rs:144
msgid "Summary"
msgstr ""
@ -299,15 +310,15 @@ msgstr ""
msgid "Create an account"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Username"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Password"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Password confirmation"
msgstr ""
@ -377,6 +388,12 @@ msgstr ""
msgid "Read the detailed rules"
msgstr ""
msgid "None"
msgstr ""
msgid "No description"
msgstr ""
msgid "View all"
msgstr ""
@ -392,71 +409,71 @@ msgstr ""
msgid "Advanced search"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "Article title matching these words"
msgstr ""
msgid "Title"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "Subtitle matching these words"
msgstr ""
msgid "Subtitle - byline"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "Content matching these words"
msgstr ""
msgid "Body content"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "From this date"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "To this date"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "Containing these tags"
msgstr ""
msgid "Tags"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "Posted on one of these instances"
msgstr ""
msgid "Instance domain"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "Posted by one of these authors"
msgstr ""
msgid "Authors"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "Posted on one of these blogs"
msgstr ""
msgid "Blog title"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "Written in this language"
msgstr ""
msgid "Language"
msgstr ""
# src/template_utils.rs:185
# src/template_utils.rs:305
msgid "Published under this license"
msgstr ""
@ -478,11 +495,11 @@ msgstr ""
msgid "Reset your password"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "New password"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Confirmation"
msgstr ""
@ -495,7 +512,7 @@ msgstr ""
msgid "We sent a mail to the address you gave us, with a link to reset your password."
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "E-mail"
msgstr ""
@ -505,14 +522,14 @@ msgstr ""
msgid "Login"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Username or email"
msgstr ""
msgid "Publish"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Subtitle"
msgstr ""
@ -525,24 +542,21 @@ msgstr ""
msgid "Upload media"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Tags, separated by commas"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "License"
msgstr ""
# src/template_utils.rs:148
# src/template_utils.rs:225
msgid "Leave it empty to reserve all rights"
msgstr ""
msgid "Illustration"
msgstr ""
msgid "None"
msgstr ""
msgid "This is a draft, don't publish it yet."
msgstr ""
@ -596,7 +610,7 @@ msgstr ""
msgid "Comments"
msgstr ""
# src/template_utils.rs:144
# src/template_utils.rs:217
msgid "Content warning"
msgstr ""
@ -642,6 +656,33 @@ msgstr ""
msgid "Sorry about that. If you think this is a bug, please report it."
msgstr ""
msgid "Edit \"{}\""
msgstr ""
msgid "Description"
msgstr ""
msgid "You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
msgid "Upload images"
msgstr ""
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
msgid "Update blog"
msgstr ""
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
msgid "Permanently delete this blog"
msgstr ""
msgid "New Blog"
msgstr ""
@ -651,24 +692,17 @@ msgstr ""
msgid "Create blog"
msgstr ""
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] ""
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] ""
msgid "No posts to see here yet."
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr ""
msgid "Be very careful, any action taken here can't be reversed."
msgstr ""
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] ""
msgid "Permanently delete this blog"
msgid "No posts to see here yet."
msgstr ""
msgid "Articles tagged \"{0}\""
@ -695,9 +729,6 @@ msgstr ""
msgid "Media upload"
msgstr ""
msgid "Description"
msgstr ""
msgid "Useful for visually impaired people, as well as licensing information"
msgstr ""

View file

@ -44,6 +44,18 @@ msgstr "Você precisa estar logado para criar um novo blog"
msgid "You are not allowed to delete this blog."
msgstr "Você não é autor neste blog."
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "Você não é autor neste blog."
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "Você não é autor neste blog."
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "Você não é autor neste blog."
msgid "You need to be logged in order to like a post"
msgstr "Você precisa estar logado para gostar de um post"
@ -388,6 +400,13 @@ msgstr "Acolhe <em>{0}</em> pessoas"
msgid "Read the detailed rules"
msgstr "Leia as regras detalhadas"
msgid "None"
msgstr "Nenhum"
#, fuzzy
msgid "No description"
msgstr "Descrição longa"
msgid "View all"
msgstr "Ver tudo"
@ -561,9 +580,6 @@ msgstr ""
msgid "Illustration"
msgstr "Ilustração"
msgid "None"
msgstr "Nenhum"
msgid "This is a draft, don't publish it yet."
msgstr "Este artigo é um rascunho, será publicado mais tarde."
@ -672,6 +688,39 @@ msgid "Sorry about that. If you think this is a bug, please report it."
msgstr ""
"Desculpa por isso. Se você acha que isso é um bug, por favor, relate-o."
#, fuzzy
msgid "Edit \"{}\""
msgstr "Mudar {0}"
msgid "Description"
msgstr "Descrição"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "Upload images"
msgstr "Carregar"
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "Update blog"
msgstr "Criar o blog"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr "Cuidado, qualquer acção tomada aqui não pode ser anulada."
#, fuzzy
msgid "Permanently delete this blog"
msgstr "Suprimir este blog"
#, fuzzy
msgid "New Blog"
msgstr "Novo blog"
@ -682,32 +731,21 @@ msgstr "Criar um blog"
msgid "Create blog"
msgstr "Criar o blog"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "Novo artigo"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Um autor neste blog: "
msgstr[1] "{0} autores neste blog: "
#, fuzzy
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "Um artigo neste blog"
msgstr[1] "{0} artigos neste blog"
msgid "No posts to see here yet."
msgstr "Ainda não há posts para ver."
msgid "New article"
msgstr "Novo artigo"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
msgstr "Cuidado, qualquer acção tomada aqui não pode ser anulada."
#, fuzzy
msgid "Permanently delete this blog"
msgstr "Suprimir este blog"
msgid "Articles tagged \"{0}\""
msgstr "Artigos marcados com \"{0}\""
@ -735,9 +773,6 @@ msgstr "Detalhes da mídia"
msgid "Media upload"
msgstr "Carregamento de mídia"
msgid "Description"
msgstr "Descrição"
msgid "Useful for visually impaired people, as well as licensing information"
msgstr ""
@ -768,6 +803,12 @@ msgstr "Copie-o em seus artigos para inserir esta mídia."
msgid "Use as avatar"
msgstr "Utilizar como avatar"
#, fuzzy
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "Um artigo neste blog"
#~ msgstr[1] "{0} artigos neste blog"
#~ msgid "{0}'s followers"
#~ msgstr "Seguidores de {0}"

View file

@ -45,6 +45,18 @@ msgstr "Вы должны войти чтобы написать новый по
msgid "You are not allowed to delete this blog."
msgstr "Вы не автор этого блога."
#, fuzzy
msgid "You are not allowed to edit this blog."
msgstr "Вы не автор этого блога."
#, fuzzy
msgid "You can't use this media as blog icon."
msgstr "Вы не автор этого блога."
#, fuzzy
msgid "You can't use this media as blog banner."
msgstr "Вы не автор этого блога."
#, fuzzy
msgid "You need to be logged in order to like a post"
msgstr "Вы должны войти чтобы отмечать понравившиеся посты"
@ -412,6 +424,13 @@ msgstr ""
msgid "Read the detailed rules"
msgstr "Прочитать подробные правила"
msgid "None"
msgstr "Нет"
#, fuzzy
msgid "No description"
msgstr "Длинное описание"
msgid "View all"
msgstr "Показать все"
@ -578,9 +597,6 @@ msgstr "Оставьте пустым если нет"
msgid "Illustration"
msgstr "Иллюстрация"
msgid "None"
msgstr "Нет"
#, fuzzy
msgid "This is a draft, don't publish it yet."
msgstr "Этот пост ещё не опубликован."
@ -707,34 +723,29 @@ msgstr ""
"ней."
#, fuzzy
msgid "New Blog"
msgstr "Новый блог"
msgid "Edit \"{}\""
msgstr "Редактировать"
msgid "Create a blog"
msgstr "Создать блог"
msgid "Description"
msgstr "Описание"
msgid "Create blog"
msgstr "Создать блог"
msgid ""
"You can upload images to your gallery, to use them as blog icons or banners."
msgstr ""
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Один автор в этом блоге: "
msgstr[1] "{0} автора в этом блоге: "
msgstr[2] "{0} авторов в этом блоге: "
msgid "Upload images"
msgstr "Загрузить"
msgid "Blog icon"
msgstr ""
msgid "Blog banner"
msgstr ""
#, fuzzy
msgid "There's one article on this blog"
msgid_plural "There are {0} articles on this blog"
msgstr[0] "Один пост в этом блоге"
msgstr[1] "{0} поста в этом блоге"
msgstr[2] "{0} постов в этом блоге"
msgid "No posts to see here yet."
msgstr "Здесь пока нет постов."
msgid "New article"
msgstr "Новая статья"
msgid "Update blog"
msgstr "Создать блог"
#, fuzzy
msgid "Be very careful, any action taken here can't be reversed."
@ -745,6 +756,32 @@ msgstr ""
msgid "Permanently delete this blog"
msgstr "Удалить этот блог"
#, fuzzy
msgid "New Blog"
msgstr "Новый блог"
msgid "Create a blog"
msgstr "Создать блог"
msgid "Create blog"
msgstr "Создать блог"
msgid "{}'s icon"
msgstr ""
msgid "New article"
msgstr "Новая статья"
#, fuzzy
msgid "There's one author on this blog: "
msgid_plural "There are {0} authors on this blog: "
msgstr[0] "Один автор в этом блоге: "
msgstr[1] "{0} автора в этом блоге: "
msgstr[2] "{0} авторов в этом блоге: "
msgid "No posts to see here yet."
msgstr "Здесь пока нет постов."
#, fuzzy
msgid "Articles tagged \"{0}\""
msgstr "Статьи, отмеченные тегом «{0}»"
@ -774,9 +811,6 @@ msgstr "Детали медиафайла"
msgid "Media upload"
msgstr "Загрузка медиафайлов"
msgid "Description"
msgstr "Описание"
#, fuzzy
msgid "Useful for visually impaired people, as well as licensing information"
msgstr "Описание для лиц с нарушениями зрения и информация о лицензии"
@ -808,6 +842,13 @@ msgstr ""
msgid "Use as avatar"
msgstr "Использовать как аватар"
#, fuzzy
#~ msgid "There's one article on this blog"
#~ msgid_plural "There are {0} articles on this blog"
#~ msgstr[0] "Один пост в этом блоге"
#~ msgstr[1] "{0} поста в этом блоге"
#~ msgstr[2] "{0} постов в этом блоге"
#, fuzzy
#~ msgid "{0}'s followers"
#~ msgstr "Один подписчик"

View file

@ -127,7 +127,6 @@ Then try to restart Plume
})
.expect("Error setting Ctrl-c handler");
let mail = mail::init();
if mail.is_none() && CONFIG.rocket.as_ref().unwrap().environment.is_prod() {
println!("Warning: the email server is not configured (or not completely).");
@ -145,6 +144,8 @@ Then try to restart Plume
routes::blogs::new_auth,
routes::blogs::create,
routes::blogs::delete,
routes::blogs::edit,
routes::blogs::update,
routes::blogs::atom_feed,
routes::comments::create,
routes::comments::delete,

View file

@ -1,5 +1,6 @@
use activitypub::collection::OrderedCollection;
use atom_syndication::{Entry, FeedBuilder};
use diesel::SaveChangesDsl;
use rocket::{
http::ContentType,
request::LenientForm,
@ -11,7 +12,10 @@ use validator::{Validate, ValidationError, ValidationErrors};
use plume_common::activity_pub::{ActivityStream, ApRequest};
use plume_common::utils;
use plume_models::{blog_authors::*, blogs::*, db_conn::DbConn, instance::Instance, posts::Post};
use plume_models::{
blog_authors::*, blogs::*, db_conn::DbConn, instance::Instance, medias::*, posts::Post,
safe_string::SafeString, users::User, Connection,
};
use routes::{errors::ErrorPage, Page, PlumeRocket};
use template_utils::Ructe;
@ -28,13 +32,10 @@ pub fn details(name: String, page: Option<Page>, rockets: PlumeRocket) -> Result
Ok(render!(blogs::details(
&(&*conn, &intl.catalog, user.clone()),
blog.clone(),
blog,
authors,
articles_count,
page.0,
Page::total(articles_count as i32),
user.and_then(|x| x.is_author_in(&*conn, &blog).ok())
.unwrap_or(false),
posts
)))
}
@ -170,6 +171,141 @@ pub fn delete(name: String, rockets: PlumeRocket) -> Result<Redirect, Ructe> {
}
}
#[derive(FromForm, Validate)]
pub struct EditForm {
#[validate(custom(function = "valid_slug", message = "Invalid name"))]
pub title: String,
pub summary: String,
pub icon: Option<i32>,
pub banner: Option<i32>,
}
#[get("/~/<name>/edit")]
pub fn edit(
conn: DbConn,
name: String,
user: Option<User>,
intl: I18n,
) -> Result<Ructe, ErrorPage> {
let blog = Blog::find_by_fqn(&*conn, &name)?;
if user
.clone()
.and_then(|u| u.is_author_in(&*conn, &blog).ok())
.unwrap_or(false)
{
let user = user.expect("blogs::edit: User was None while it shouldn't");
let medias = Media::for_user(&*conn, user.id).expect("Couldn't list media");
Ok(render!(blogs::edit(
&(&*conn, &intl.catalog, Some(user)),
&blog,
medias,
&EditForm {
title: blog.title.clone(),
summary: blog.summary.clone(),
icon: blog.icon_id,
banner: blog.banner_id,
},
ValidationErrors::default()
)))
} else {
// TODO actually return 403 error code
Ok(render!(errors::not_authorized(
&(&*conn, &intl.catalog, user),
i18n!(intl.catalog, "You are not allowed to edit this blog.")
)))
}
}
/// Returns true if the media is owned by `user` and is a picture
fn check_media(conn: &Connection, id: i32, user: &User) -> bool {
if let Ok(media) = Media::get(conn, id) {
media.owner_id == user.id && media.category() == MediaCategory::Image
} else {
false
}
}
#[put("/~/<name>/edit", data = "<form>")]
pub fn update(
conn: DbConn,
name: String,
user: Option<User>,
intl: I18n,
form: LenientForm<EditForm>,
) -> Result<Redirect, Ructe> {
let mut blog = Blog::find_by_fqn(&*conn, &name).expect("blog::update: blog not found");
if user
.clone()
.and_then(|u| u.is_author_in(&*conn, &blog).ok())
.unwrap_or(false)
{
let user = user.expect("blogs::edit: User was None while it shouldn't");
form.validate()
.and_then(|_| {
if let Some(icon) = form.icon {
if !check_media(&*conn, icon, &user) {
let mut errors = ValidationErrors::new();
errors.add(
"",
ValidationError {
code: Cow::from("icon"),
message: Some(Cow::from(i18n!(
intl.catalog,
"You can't use this media as blog icon."
))),
params: HashMap::new(),
},
);
return Err(errors);
}
}
if let Some(banner) = form.banner {
if !check_media(&*conn, banner, &user) {
let mut errors = ValidationErrors::new();
errors.add(
"",
ValidationError {
code: Cow::from("banner"),
message: Some(Cow::from(i18n!(
intl.catalog,
"You can't use this media as blog banner."
))),
params: HashMap::new(),
},
);
return Err(errors);
}
}
blog.title = form.title.clone();
blog.summary = form.summary.clone();
blog.summary_html = SafeString::new(&utils::md_to_html(&form.summary, "", true).0);
blog.icon_id = form.icon;
blog.banner_id = form.banner;
blog.save_changes::<Blog>(&*conn)
.expect("Couldn't save blog changes");
Ok(Redirect::to(uri!(details: name = name, page = _)))
})
.map_err(|err| {
let medias = Media::for_user(&*conn, user.id).expect("Couldn't list media");
render!(blogs::edit(
&(&*conn, &intl.catalog, Some(user)),
&blog,
medias,
&*form,
err
))
})
} else {
// TODO actually return 403 error code
Err(render!(errors::not_authorized(
&(&*conn, &intl.catalog, user),
i18n!(intl.catalog, "You are not allowed to edit this blog.")
)))
}
}
#[get("/~/<name>/outbox")]
pub fn outbox(name: String, conn: DbConn) -> Option<ActivityStream<OrderedCollection>> {
let blog = Blog::find_by_fqn(&*conn, &name).ok()?;

View file

@ -44,6 +44,7 @@ pub fn create(
&Instance::get_local(&conn)
.expect("comments::create: local instance error")
.public_domain,
true,
);
let comm = Comment::insert(
&*conn,

View file

@ -263,6 +263,7 @@ pub fn update(
&Instance::get_local(&conn)
.expect("posts::update: Error getting local instance")
.public_domain,
false,
);
// update publication date if when this article is no longer a draft
@ -422,6 +423,7 @@ pub fn create(
&Instance::get_local(&conn)
.expect("post::create: local instance error")
.public_domain,
false,
);
let searcher = rockets.searcher;

View file

@ -129,3 +129,7 @@ form.new-post {
input[type="submit"]:hover { background: $lightgray; }
-webkit-appearance: none;
}
.button + .button {
margin-left: 1em;
}

View file

@ -137,6 +137,10 @@ p.error {
margin: 0px;
}
.user .avatar.medium {
margin-left: 0px;
}
.badge {
margin-right: 1em;
padding: 0.35em 1em;

View file

@ -5,7 +5,7 @@
@use template_utils::*;
@use routes::*;
@(ctx: BaseContext, blog: Blog, authors: &[User], total_articles: i64, page: i32, n_pages: i32, is_author: bool, posts: Vec<Post>)
@(ctx: BaseContext, blog: Blog, authors: &[User], page: i32, n_pages: i32, posts: Vec<Post>)
@:base(ctx, blog.title.clone(), {}, {
<a href="@uri!(blogs::details: name = &blog.fqn, page = _)">@blog.title</a>
@ -19,17 +19,36 @@
}
</div>
<div class="h-feed">
<h1><span class="p-name">@blog.title</span> <small>~@blog.fqn</small></h1>
<p>@blog.summary</p>
<p>
@i18n!(ctx.1, "There's one author on this blog: ", "There are {0} authors on this blog: "; authors.len())
@for author in authors {
<a class="author p-author" href="@uri!(user::details: name = &author.fqn)">@author.name()</a>
}
</p>
<p>
@i18n!(ctx.1, "There's one article on this blog", "There are {0} articles on this blog"; total_articles)
</p>
@if let Some(banner_url) = blog.banner_url(ctx.0) {
<div class="cover" style="background-image: url('@Html(banner_url.clone())')"></div>
<img class="hidden u-photo" src="@banner_url"/>
}
<div class="h-card">
<div class="user">
<div class="flex wrap">
<div class="avatar medium" style="background-image: url('@blog.icon_url(ctx.0)');" aria-label="@i18n!(ctx.1, "{}'s icon"; &blog.title)"></div>
<img class="hidden u-photo" src="@blog.icon_url(ctx.0)"/>
<h1 class="grow flex vertical">
<span class="p-name">@blog.title</span>
<small>~@blog.fqn</small>
</h1>
@if ctx.2.clone().and_then(|u| u.is_author_in(ctx.0, &blog).ok()).unwrap_or(false) {
<a href="@uri!(posts::new: blog = &blog.fqn)" class="button">@i18n!(ctx.1, "New article")</a>
<a href="@uri!(blogs::edit: name = &blog.fqn)" class="button">@i18n!(ctx.1, "Edit")</a>
}
</div>
<main class="user-summary">
<p>
@i18n!(ctx.1, "There's one author on this blog: ", "There are {0} authors on this blog: "; authors.len())
@for (i, author) in authors.iter().enumerate() {@if i >= 1 {, }
<a class="author p-author" href="@uri!(user::details: name = &author.fqn)">@author.name()</a>}
</p>
@Html(blog.summary_html.clone())
</main>
</div>
<section>
<h2>
@ -39,9 +58,6 @@
@if posts.is_empty() {
<p>@i18n!(ctx.1, "No posts to see here yet.")</p>
}
@if is_author {
<a href="@uri!(posts::new: blog = &blog.fqn)" class="button inline-block">@i18n!(ctx.1, "New article")</a>
}
<div class="cards">
@for article in posts {
@:post_card(ctx, article)
@ -50,11 +66,4 @@
@paginate(ctx.1, page, n_pages)
</section>
</div>
@if is_author {
<h2>@i18n!(ctx.1, "Danger zone")</h2>
<p>@i18n!(ctx.1, "Be very careful, any action taken here can't be reversed.")</p>
<form method="post" action="@uri!(blogs::delete: name = &blog.fqn)">
<input type="submit" class="inline-block button destructive" value="@i18n!(ctx.1, "Permanently delete this blog")">
</form>
}
})

View file

@ -0,0 +1,42 @@
@use validator::ValidationErrors;
@use plume_models::blogs::Blog;
@use plume_models::medias::Media;
@use routes::blogs;
@use routes::blogs::EditForm;
@use routes::medias;
@use template_utils::*;
@use templates::base;
@use templates::partials::image_select;
@(ctx: BaseContext, blog: &Blog, medias: Vec<Media>, form: &EditForm, errors: ValidationErrors)
@:base(ctx, i18n!(ctx.1, "Edit \"{}\""; &blog.title), {}, {
<a href="@uri!(blogs::details: name = &blog.fqn, page = _)">@blog.title</a>
}, {
<h1>@i18n!(ctx.1, "Edit \"{}\""; &blog.title)</h1>
<form method="post" action="@uri!(blogs::update: name = &blog.fqn)">
<!-- Rocket hack to use various HTTP methods -->
<input type=hidden name="_method" value="put">
@input!(ctx.1, title (text), "Title", form, errors.clone(), "minlenght=\"1\"")
<label for="summary">@i18n!(ctx.1, "Description")<small>@i18n!(ctx.1, "Markdown syntax is supported")</small></label>
<textarea id="summary" name="summary" rows="20">@form.summary</textarea>
<p>
@i18n!(ctx.1, "You can upload images to your gallery, to use them as blog icons or banners.")
<a href="@uri!(medias::new)">@i18n!(ctx.1, "Upload images")</a>
</p>
@:image_select(ctx, "icon", i18n!(ctx.1, "Blog icon"), true, medias.clone(), form.icon)
@:image_select(ctx, "banner", i18n!(ctx.1, "Blog banner"), true, medias, form.banner)
<input type="submit" value="@i18n!(ctx.1, "Update blog")"/>
</form>
<h2>@i18n!(ctx.1, "Danger zone")</h2>
<p>@i18n!(ctx.1, "Be very careful, any action taken here can't be reversed.")</p>
<form method="post" action="@uri!(blogs::delete: name = &blog.fqn)">
<input type="submit" class="inline-block button destructive" value="@i18n!(ctx.1, "Permanently delete this blog")">
</form>
})

View file

@ -0,0 +1,25 @@
@use template_utils::*;
@use plume_models::medias::*;
@(ctx: BaseContext, id: &str, title: String, optional: bool, medias: Vec<Media>, selected: Option<i32>)
<label for="@id">
@title
@if optional {
<small>@i18n!(ctx.1, "Optional")</small>
}
</label>
<select id="@id" name="@id">
<option value="none" @if selected.is_none() { selected }>@i18n!(ctx.1, "None")</option>
@for media in medias {
@if media.category() == MediaCategory::Image {
<option value="@media.id" @if selected.map(|c| c == media.id).unwrap_or(false) { selected }>
@if !media.alt_text.is_empty() {
@media.alt_text
} else {
@media.content_warning.unwrap_or(i18n!(ctx.1, "No description"))
}
</option>
}
}
</select>

View file

@ -47,7 +47,7 @@
</div>
@if article.cover_id.is_some() {
<div class="cover" style="background-image: url('@Html(article.cover_url(ctx.0).unwrap_or_default())')"></div>
<img class="hidden u-photo" src="@article.cover_url(ctx.0).unwrap_or_default()" />
<img class="hidden u-photo" src="@article.cover_url(ctx.0).unwrap_or_default()"/>
}
<article class="e-content">
@Html(&article.content)

View file

@ -1,4 +1,5 @@
@use templates::base;
@use templates::partials::image_select;
@use template_utils::*;
@use validator::{ValidationErrors, ValidationErrorsKind};
@use std::borrow::Cow;
@ -42,21 +43,7 @@
@input!(ctx.1, license (optional text), "License", "Leave it empty to reserve all rights", form, errors, "")
<label for="cover">@i18n!(ctx.1, "Illustration")<small>@i18n!(ctx.1, "Optional")</small></label>
<select id="cover" name="cover">
<option value="none" @if form.cover.is_none() { selected }>@i18n!(ctx.1, "None")</option>
@for media in medias {
@if media.category() == MediaCategory::Image {
<option value="@media.id" @if form.cover.map(|c| c == media.id).unwrap_or(false) { selected }>
@if !media.alt_text.is_empty() {
@media.alt_text
} else {
@media.content_warning.unwrap_or_default()
}
</option>
}
}
</select>
@:image_select(ctx, "cover", i18n!(ctx.1, "Illustration"), true, medias, form.cover)
@if is_draft {
<label for="draft">

View file

@ -17,7 +17,11 @@
<div class="cards">
@for blog in blogs {
<div class="card">
@if blog.banner_id.is_some() {
<div class="cover" style="background-image: url('@Html(blog.banner_url(ctx.0).unwrap_or_default())')"></div>
}
<h3><a href="@uri!(blogs::details: name = blog.actor_id, page = _)">@blog.title</a></h3>
<main><p>@Html(blog.summary_html)</p></main>
</div>
}
</div>