~vpzom/hitide

dca1c01fce3fba59cccb8ec014aeda1862847091 — Colin Reeder 1 year, 1 month ago ff300d9
Use placeholders for more lang texts
4 files changed, 266 insertions(+), 130 deletions(-)

M res/lang/en.ftl
M src/components/mod.rs
M src/routes/administration.rs
M src/routes/posts.rs
M res/lang/en.ftl => res/lang/en.ftl +15 -15
@@ 1,4 1,3 @@
a_comment = a comment
about = About
about_title = About this instance
about_what_is = What is lotide?


@@ 15,14 14,13 @@ administration_edit = Edit Instance Details
administration_edit_invitations_enabled = Invitations:
administration_edit_signup_allowed = Public Signups:
administration_invitation_creation_requirement = Invitations can be created by
administration_invitations_enabled = Invitations are currently
administration_signup_allowed = Signups are currently
administration_invitations_enabled = Invitations are currently { $part_enabled }
administration_signup_allowed = Signups are currently { $part_allowed }
all = All
all_title = The Whole Known Network
allowed_false = not allowed
allowed_true = allowed
and_more = …and more
by = by
comment = Comment
comments = Comments
comment_attachment_prefix = Attachment:


@@ 61,7 59,7 @@ enabled_false = disabled
fetch = Fetch
flag_comment_prompt = Add a comment:
flag_dismiss = Dismiss
flagged_by = Flagged by
flagged_by = Flagged by { $part_user }
flags = Flags
flags_title_community = Flags for this Community
flags_title_other = Flags


@@ 98,10 96,8 @@ moderation_dashboard_some = Moderation Dashboard (Pending Actions)
moderators = Moderators
modlog = Modlog
modlog_event_approve_post = Post Approved:
modlog_event_delete_post_1 = Deleted a post by
modlog_event_delete_post_2 = in
modlog_event_delete_comment_1 = Deleted a comment by
modlog_event_delete_comment_2 = on
modlog_event_delete_post = Deleted a post by { $part_user } in { $part_community }
modlog_event_delete_comment = Deleted a comment by { $part_user } in { $part_community }
modlog_event_reject_post = Post Rejected:
modlog_event_suspend_user = User Suspended:
modlog_event_unsuspend_user = User Unsuspended:


@@ 118,9 114,11 @@ not_site_admin = You are not an instance admin
nothing = Looks like there's nothing here.
nothing_yet = Looks like there's nothing here (yet!).
notifications = Notifications
notification_comment_mention_1 = You were mentioned in
notification_comment_mention = You were mentioned in { $part_comment } on { $part_post }:
notification_comment_mention_part_comment = a comment
notification_comment_reply = Reply to { $part_your_comment } on { $part_post }:
notification_comment_reply_part_your_comment = your comment
notification_post_mention = You were mentioned in a post:
on = on
on_your_post = on your post
open_menu = Open Menu
poll_new_closes_prompt = Closes in:


@@ 153,6 151,10 @@ post_new_missing_content_type = Missing Content-Type for image upload
post_new_image_prompt = Image:
post_not_approved = This post has not been approved by the community.
post_rejected = This post has been rejected by the community.
post_submitted = Submitted { $part_time }
post_submitted_by = Submitted { $part_time } by { $part_user }
post_submitted_by_to = Submitted { $part_time } by { $part_user } to { $part_community }
post_submitted_to = Submitted { $part_time } to { $part_community }
post_timeframe = Posts from:
preview = Preview
profile = Profile


@@ 163,7 165,6 @@ remove = remove
remove_upvote = Remove upvote
reply = reply
reply_submit = Reply
reply_to = Reply to
requirement_none = all users
requirement_site_admin = site admins
save = Save


@@ 179,8 180,9 @@ sort_hot = hot
sort_new = new
sort_top = top
submit = Submit
submitted = Submitted
text_with_markdown = Text (markdown supported)
thing_comment = { $part_comment } on { $part_post }:
thing_comment_part_comment = Comment
time_input_minutes = minutes
time_input_hours = hours
time_input_days = days


@@ 228,7 230,6 @@ timeframe_month = past month
timeframe_week = past week
timeframe_year = past year
title = Title
to = to
to_parent = View Parent
to_post = Comment on
unknown = [unknown]


@@ 252,7 253,6 @@ user_suspended_note = This user has been suspended.
username_prompt = Username:
view_at_source = View at Source
view_more_comments = View More Comments
your_comment = your comment
your_note = Personal Note
your_note_add = Add Personal Note
your_note_edit = Edit Personal Note

M src/components/mod.rs => src/components/mod.rs +194 -99
@@ 302,26 302,52 @@ impl<'a, T: HavingContent + 'a> render::Render for ContentView<'a, T> {
    }
}

#[render::component]
pub fn FlagItem<'a>(flag: &'a RespFlagInfo<'a>, in_community: bool, lang: &'a crate::Translator) {
    let RespFlagDetails::Post { post } = &flag.details;
pub struct FlagItem<'a> {
    pub flag: &'a RespFlagInfo<'a>,
    pub in_community: bool,
    pub lang: &'a crate::Translator,
}

    render::rsx! {
        <li class={"flagItem"}>
            <div class={"flaggedContent"}>
                <PostItemContent post={post} in_community no_user={false} lang />
            </div>
            {lang.tr(&lang::FLAGGED_BY)}{" "}<UserLink user={Some(&flag.flagger)} lang />
            {
                flag.content.as_ref().map(|content| {
                    render::rsx! {
                        <blockquote>
                            {content.content_text.as_ref()}
                        </blockquote>
                    }
                })
            }
        </li>
impl<'a> render::Render for FlagItem<'a> {
    fn render_into<W: std::fmt::Write + ?Sized>(self, w: &mut W) -> std::fmt::Result {
        let Self {
            flag,
            in_community,
            lang,
        } = self;

        let RespFlagDetails::Post { post } = &flag.details;

        render::rsx! {
            <li class={"flagItem"}>
                <div class={"flaggedContent"}>
                    <PostItemContent post={post} in_community no_user={false} lang />
                </div>
                {
                    lang::TrElements::new(
                        lang.tr(&lang::flagged_by(lang::LangPlaceholder(0))),
                        |id, w| {
                            match id {
                                0 => render::rsx! {
                                    <UserLink user={Some(&flag.flagger)} lang />
                                }.render_into(w),
                                _ => unreachable!(),
                            }
                        },
                    )
                }
                {
                    flag.content.as_ref().map(|content| {
                        render::rsx! {
                            <blockquote>
                                {content.content_text.as_ref()}
                            </blockquote>
                        }
                    })
                }
            </li>
        }
        .render_into(w)
    }
}



@@ 464,58 490,69 @@ pub fn PostItem<'a>(
    }
}

#[render::component]
pub fn PostItemContent<'a>(
pub struct PostItemContent<'a> {
    post: &'a RespPostListPost<'a>,
    in_community: bool,
    no_user: bool,
    lang: &'a crate::Translator,
) {
    let post_href = format!("/posts/{}", post.as_ref().as_ref().id);
}

    render::rsx! {
        <>
            <div class={"titleLine"}>
                <a href={post_href.clone()}>
                    {post.as_ref().as_ref().sensitive.then(|| hitide_icons::SENSITIVE.img(lang.tr(&lang::SENSITIVE)))}
                    {post.as_ref().as_ref().title.as_ref()}
                </a>
                {
                    post.as_ref().href.as_ref().map(|href| {
                        render::rsx! {
                            <em><a href={href.as_ref()}>{abbreviate_link(href)}{" ↗"}</a></em>
                        }
                    })
                }
            </div>
            <small>
                {lang.tr(&lang::SUBMITTED)}
                {" "}
                <TimeAgo since={chrono::DateTime::parse_from_rfc3339(&post.as_ref().created).unwrap()} lang />
                {
                    if no_user {
                        None
                    } else {
                        Some(render::rsx! {
                            <>
                                {" "}{lang.tr(&lang::BY)}{" "}<UserLink lang user={post.as_ref().author.as_ref()} />
                            </>
impl<'a> render::Render for PostItemContent<'a> {
    fn render_into<W: std::fmt::Write + ?Sized>(self, w: &mut W) -> std::fmt::Result {
        let Self {
            post,
            in_community,
            no_user,
            lang,
        } = self;

        let post_href = format!("/posts/{}", post.as_ref().as_ref().id);

        render::rsx! {
            <>
                <div class={"titleLine"}>
                    <a href={post_href.clone()}>
                        {post.as_ref().as_ref().sensitive.then(|| hitide_icons::SENSITIVE.img(lang.tr(&lang::SENSITIVE)))}
                        {post.as_ref().as_ref().title.as_ref()}
                    </a>
                    {
                        post.as_ref().href.as_ref().map(|href| {
                            render::rsx! {
                                <em><a href={href.as_ref()}>{abbreviate_link(href)}{" ↗"}</a></em>
                            }
                        })
                    }
                }
                {
                    if !in_community {
                        Some(render::rsx! {
                            <>{" "}{lang.tr(&lang::TO)}{" "}<CommunityLink community={&post.as_ref().community} /></>
                        })
                    } else {
                        None
                </div>
                <small>
                    {
                        lang::TrElements::new(
                            lang.tr(&match (no_user, in_community) {
                                (false, false) => lang::post_submitted_by_to(lang::LangPlaceholder(0), lang::LangPlaceholder(1), lang::LangPlaceholder(2)),
                                (false, true) => lang::post_submitted_by(lang::LangPlaceholder(0), lang::LangPlaceholder(1)),
                                (true, false) => lang::post_submitted_to(lang::LangPlaceholder(0), lang::LangPlaceholder(2)),
                                (true, true) => lang::post_submitted(lang::LangPlaceholder(0)),
                            }),
                            |id, w| {
                                match id {
                                    0 => render::rsx! {
                                        <TimeAgo since={chrono::DateTime::parse_from_rfc3339(&post.as_ref().created).unwrap()} lang />
                                    }.render_into(w),
                                    1 => render::rsx! {
                                        <UserLink lang user={post.as_ref().author.as_ref()} />
                                    }.render_into(w),
                                    2 => render::rsx! {
                                        <CommunityLink community={&post.as_ref().community} />
                                    }.render_into(w),
                                    _ => unreachable!(),
                                }
                            },
                        )
                    }
                }
                {" | "}
                <a href={post_href}>{lang.tr(&lang::post_comments_count(post.replies_count_total)).into_owned()}</a>
            </small>
        </>
                    {" | "}
                    <a href={post_href}>{lang.tr(&lang::post_comments_count(post.replies_count_total)).into_owned()}</a>
                </small>
            </>
        }.render_into(w)
    }
}



@@ 536,8 573,26 @@ impl<'a> render::Render for ThingItem<'a> {
                (render::rsx! {
                    <li>
                        <small>
                            <a href={format!("/comments/{}", comment.as_ref().id)}>{lang.tr(&lang::comment())}</a>
                            {" "}{lang.tr(&lang::on())}{" "}<a href={format!("/posts/{}", comment.post.id)}>{comment.post.title.as_ref()}</a>{":"}
                            {
                                lang::TrElements::new(
                                    lang.tr(&lang::thing_comment(lang::LangPlaceholder(0), lang::LangPlaceholder(1))),
                                    |id, w| {
                                        match id {
                                            0 => render::rsx! {
                                                <a href={format!("/comments/{}", comment.as_ref().id)}>
                                                    {lang.tr(&lang::thing_comment_part_comment())}
                                                </a>
                                            }.render_into(w),
                                            1 => render::rsx! {
                                                <a href={format!("/posts/{}", comment.post.id)}>
                                                    {comment.post.title.as_ref()}
                                                </a>
                                            }.render_into(w),
                                            _ => unreachable!(),
                                        }
                                    }
                                )
                            }
                        </small>
                        <ContentView src={comment} />
                    </li>


@@ 806,11 861,26 @@ impl<'a> render::Render for NotificationItem<'a> {
                (render::rsx! {
                    <>
                        <div>
                            {lang.tr(&lang::reply_to())}
                            {" "}
                            <a href={format!("/comments/{}", comment.as_ref().id)}>{lang.tr(&lang::your_comment())}</a>
                            {" "}{lang.tr(&lang::on())}{" "}<a href={format!("/posts/{}", post.as_ref().as_ref().id)}>{post.as_ref().as_ref().title.as_ref()}</a>
                            {":"}
                            {
                                lang::TrElements::new(
                                    lang.tr(&lang::notification_comment_reply(lang::LangPlaceholder(0), lang::LangPlaceholder(1))),
                                    |id, w| {
                                        match id {
                                            0 => render::rsx! {
                                                <a href={format!("/comments/{}", comment.as_ref().id)}>
                                                    {lang.tr(&lang::notification_comment_reply_part_your_comment())}
                                                </a>
                                            }.render_into(w),
                                            1 => render::rsx! {
                                                <a href={format!("/posts/{}", post.as_ref().as_ref().id)}>
                                                    {post.as_ref().as_ref().title.as_ref()}
                                                </a>
                                            }.render_into(w),
                                            _ => unreachable!(),
                                        }
                                    }
                                )
                            }
                        </div>
                        <div class={"body"}>
                            <small>


@@ 827,13 897,26 @@ impl<'a> render::Render for NotificationItem<'a> {
                (render::rsx! {
                    <>
                        <div>
                            {lang.tr(&lang::notification_comment_mention_1())}{" "}
                            <a href={format!("/comments/{}", comment.as_ref().id)}>{lang.tr(&lang::a_comment())}</a>
                            {" "}{lang.tr(&lang::on())}{" "}
                            <a href={format!("/posts/{}", post.as_ref().as_ref().id)}>
                                {post.as_ref().as_ref().title.as_ref()}
                            </a>
                            {":"}
                            {
                                lang::TrElements::new(
                                    lang.tr(&lang::notification_comment_mention(lang::LangPlaceholder(0), lang::LangPlaceholder(1))),
                                    |id, w| {
                                        match id {
                                            0 => render::rsx! {
                                                <a href={format!("/comments/{}", comment.as_ref().id)}>
                                                    {lang.tr(&lang::notification_comment_mention_part_comment())}
                                                </a>
                                            }.render_into(w),
                                            1 => render::rsx! {
                                                <a href={format!("/posts/{}", post.as_ref().as_ref().id)}>
                                                    {post.as_ref().as_ref().title.as_ref()}
                                                </a>
                                            }.render_into(w),
                                            _ => unreachable!(),
                                        }
                                    },
                                )
                            }
                            <div class={"body"}>
                                <small>
                                    <cite><UserLink lang user={comment.author.as_ref()} /></cite>


@@ 873,31 956,43 @@ impl<'a> render::Render for SiteModlogEventItem<'a> {

        match &event.details {
            RespSiteModlogEventDetails::DeletePost { author, community } => {
                (render::rsx! {
                    <>
                        {lang.tr(&lang::MODLOG_EVENT_DELETE_POST_1)}
                        {" "}
                        <UserLink user={Some(author)} lang={&lang} />
                        {" "}
                        {lang.tr(&lang::MODLOG_EVENT_DELETE_POST_2)}
                        {" "}
                        <CommunityLink community />
                    </>
                })
                lang::TrElements::new(
                    lang.tr(&lang::modlog_event_delete_post(
                        lang::LangPlaceholder(0),
                        lang::LangPlaceholder(1),
                    )),
                    |id, w| match id {
                        0 => render::rsx! {
                            <UserLink user={Some(author)} lang={&lang} />
                        }
                        .render_into(w),
                        1 => render::rsx! {
                            <CommunityLink community />
                        }
                        .render_into(w),
                        _ => unreachable!(),
                    },
                )
                .render_into(writer)?;
            }
            RespSiteModlogEventDetails::DeleteComment { author, post } => {
                (render::rsx! {
                    <>
                        {lang.tr(&lang::MODLOG_EVENT_DELETE_COMMENT_1)}
                        {" "}
                        <UserLink user={Some(author)} lang={&lang} />
                        {" "}
                        {lang.tr(&lang::MODLOG_EVENT_DELETE_COMMENT_2)}
                        {" "}
                        <a href={format!("/posts/{}", post.id)}>{post.title.as_ref()}</a>
                    </>
                })
                lang::TrElements::new(
                    lang.tr(&lang::modlog_event_delete_comment(
                        lang::LangPlaceholder(0),
                        lang::LangPlaceholder(1),
                    )),
                    |id, w| match id {
                        0 => render::rsx! {
                            <UserLink user={Some(author)} lang={&lang} />
                        }
                        .render_into(w),
                        1 => render::rsx! {
                            <a href={format!("/posts/{}", post.id)}>{post.title.as_ref()}</a>
                        }
                        .render_into(w),
                        _ => unreachable!(),
                    },
                )
                .render_into(writer)?;
            }
            RespSiteModlogEventDetails::SuspendUser { user } => {

M src/routes/administration.rs => src/routes/administration.rs +35 -12
@@ 5,6 5,7 @@ use super::{
use crate::components::{HTPage, MaybeFillOption, MaybeFillTextArea};
use crate::lang;
use crate::resp_types::RespInstanceInfo;
use render::Render;
use std::borrow::Cow;
use std::collections::HashMap;
use std::convert::TryInto;


@@ 53,20 54,42 @@ async fn page_administration(
            <a href={"/administration/edit"}>{lang.tr(&lang::administration_edit())}</a>
            <ul>
                <li>
                    {lang.tr(&lang::ADMINISTRATION_SIGNUP_ALLOWED)}{" "}
                    <strong>{lang.tr(if api_res.signup_allowed {
                        &lang::ALLOWED_TRUE
                    } else {
                        &lang::ALLOWED_FALSE
                    })}</strong>
                    {
                        lang::TrElements::new(
                            lang.tr(&lang::administration_signup_allowed(lang::LangPlaceholder(0))),
                            |id, w| {
                                match id {
                                    0 => render::rsx! {
                                        <strong>{lang.tr(if api_res.signup_allowed {
                                            &lang::ALLOWED_TRUE
                                        } else {
                                            &lang::ALLOWED_FALSE
                                        })}</strong>
                                    }.render_into(w),
                                    _ => unreachable!(),
                                }
                            }
                        )
                    }
                </li>
                <li>
                    {lang.tr(&lang::ADMINISTRATION_INVITATIONS_ENABLED)}{" "}
                    <strong>{lang.tr(if api_res.invitations_enabled {
                        &lang::ENABLED_TRUE
                    } else {
                        &lang::ENABLED_FALSE
                    })}</strong>
                    {
                        lang::TrElements::new(
                            lang.tr(&lang::administration_invitations_enabled(lang::LangPlaceholder(0))),
                            |id, w| {
                                match id {
                                    0 => render::rsx! {
                                        <strong>{lang.tr(if api_res.invitations_enabled {
                                            &lang::ENABLED_TRUE
                                        } else {
                                            &lang::ENABLED_FALSE
                                        })}</strong>
                                    }.render_into(w),
                                    _ => unreachable!(),
                                }
                            }
                        )
                    }
                    {
                        if api_res.invitations_enabled {
                            Some(render::rsx! {

M src/routes/posts.rs => src/routes/posts.rs +22 -4
@@ 14,6 14,7 @@ use crate::resp_types::{
    RespPostInfo,
};
use crate::util::author_is_me;
use render::Render;
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::HashMap;


@@ 150,6 151,8 @@ async fn page_post_inner(

    let title = post.as_ref().as_ref().title.as_ref();

    let created = chrono::DateTime::parse_from_rfc3339(&post.as_ref().created)?;

    Ok(html_response(render::html! {
        <HTPage base_data={&base_data} lang={&lang} title={title}>
            {


@@ 240,10 243,25 @@ async fn page_post_inner(
            </div>
            <br />
            <p>
                {lang.tr(&lang::submitted())}
                {" "}<TimeAgo since={chrono::DateTime::parse_from_rfc3339(&post.as_ref().created)?} lang={&lang} />
                {" "}{lang.tr(&lang::by())}{" "}<UserLink lang={&lang} user={post.as_ref().author.as_ref()} />
                {" "}{lang.tr(&lang::to())}{" "}<CommunityLink community={&post.as_ref().community} />
                {
                    lang::TrElements::new(
                        lang.tr(&lang::post_submitted_by_to(lang::LangPlaceholder(0), lang::LangPlaceholder(1), lang::LangPlaceholder(2))),
                        |id, w| {
                            match id {
                                0 => render::rsx! {
                                    <TimeAgo since={created} lang={&lang} />
                                }.render_into(w),
                                1 => render::rsx! {
                                    <UserLink lang={&lang} user={post.as_ref().author.as_ref()} />
                                }.render_into(w),
                                2 => render::rsx! {
                                    <CommunityLink community={&post.as_ref().community} />
                                }.render_into(w),
                                _ => unreachable!(),
                            }
                        }
                    )
                }
            </p>
            {
                post.as_ref().href.as_ref().map(|href| {