mirror of
https://github.com/astuto/astuto.git
synced 2025-12-14 18:57:51 +01:00
committed by
GitHub
parent
ba86e81aa0
commit
78049a820c
1
Gemfile
1
Gemfile
@@ -4,6 +4,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
||||
ruby '2.6.6'
|
||||
|
||||
gem 'rails', '6.0.4.7'
|
||||
gem 'i18n-js'
|
||||
|
||||
gem 'pg', '>= 0.18', '< 2.0'
|
||||
|
||||
|
||||
@@ -112,6 +112,8 @@ GEM
|
||||
activesupport (>= 5.0)
|
||||
i18n (1.10.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
i18n-js (3.9.2)
|
||||
i18n (>= 0.6.6)
|
||||
jbuilder (2.11.5)
|
||||
actionview (>= 5.0.0)
|
||||
activesupport (>= 5.0.0)
|
||||
@@ -297,6 +299,7 @@ DEPENDENCIES
|
||||
capybara (>= 2.15)
|
||||
devise (= 4.7.3)
|
||||
factory_bot_rails (~> 5.0.2)
|
||||
i18n-js
|
||||
jbuilder (~> 2.7)
|
||||
kaminari (~> 1.2.1)
|
||||
listen (>= 3.0.5, < 3.2)
|
||||
|
||||
@@ -11,13 +11,13 @@ module Admin
|
||||
|
||||
def authenticate_admin
|
||||
unless user_signed_in?
|
||||
flash[:alert] = 'You must be logged in to access this page.'
|
||||
flash[:alert] = t('backend.errors.not_logged_in')
|
||||
redirect_to new_user_session_path
|
||||
return
|
||||
end
|
||||
|
||||
unless current_user.admin?
|
||||
flash[:alert] = 'You do not have the privilegies to access this page.'
|
||||
flash[:alert] = t('backend.errors.not_enough_privileges')
|
||||
redirect_to root_path
|
||||
return
|
||||
end
|
||||
|
||||
@@ -20,7 +20,7 @@ class BoardsController < ApplicationController
|
||||
render json: board, status: :created
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.board.create', message: board.errors.full_messages)
|
||||
error: board.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -35,7 +35,7 @@ class BoardsController < ApplicationController
|
||||
print board.errors.full_messages
|
||||
|
||||
render json: {
|
||||
error: I18n.t('errors.board.update', message: board.errors.full_messages)
|
||||
error: board.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -49,7 +49,7 @@ class BoardsController < ApplicationController
|
||||
}, status: :accepted
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.board.destroy', message: board.errors.full_messages)
|
||||
error: board.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -67,7 +67,7 @@ class BoardsController < ApplicationController
|
||||
render json: workflow_output
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t("errors.board.update_order")
|
||||
error: t("backend.errors.board.update_order")
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,7 +30,7 @@ class CommentsController < ApplicationController
|
||||
), status: :created
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.comment.create', message: comment.errors.full_messages)
|
||||
error: comment.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -41,7 +41,7 @@ class CommentsController < ApplicationController
|
||||
comment.assign_attributes(comment_params)
|
||||
|
||||
if !current_user.power_user? && current_user.id != post.user_id
|
||||
render json: I18n.t('errors.unauthorized'), status: :unauthorized
|
||||
render json: t('backend.errors.unauthorized'), status: :unauthorized
|
||||
return
|
||||
end
|
||||
|
||||
@@ -51,7 +51,7 @@ class CommentsController < ApplicationController
|
||||
)
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.comment.update', message: comment.errors.full_messages)
|
||||
error: comment.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,7 +20,7 @@ class FollowsController < ApplicationController
|
||||
}, status: :created
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.follows.create', message: follow.errors.full_messages)
|
||||
error: follow.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -37,7 +37,7 @@ class FollowsController < ApplicationController
|
||||
}, status: :accepted
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.follow.destroy', message: follow.errors.full_messages)
|
||||
error: follow.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ class LikesController < ApplicationController
|
||||
}, status: :created
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.likes.create', message: like.errors.full_messages)
|
||||
error: like.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -42,7 +42,7 @@ class LikesController < ApplicationController
|
||||
}, status: :accepted
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.likes.destroy', message: like.errors.full_messages)
|
||||
error: like.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,7 +16,7 @@ class PostStatusesController < ApplicationController
|
||||
render json: post_status, status: :created
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.post_status.create', message: post_status.errors.full_messages)
|
||||
error: post_status.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -29,7 +29,7 @@ class PostStatusesController < ApplicationController
|
||||
render json: post_status, status: :ok
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.post_status.update', message: post_status.errors.full_messages)
|
||||
error: post_status.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -43,7 +43,7 @@ class PostStatusesController < ApplicationController
|
||||
}, status: :accepted
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.post_statuses.destroy', message: post_status.errors.full_messages)
|
||||
error: post_status.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -61,7 +61,7 @@ class PostStatusesController < ApplicationController
|
||||
render json: workflow_output
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t("errors.post_status.update_order")
|
||||
error: t("backend.errors.post_status.update_order")
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,7 +33,7 @@ class PostsController < ApplicationController
|
||||
render json: post, status: :created
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.post.create', message: post.errors.full_messages)
|
||||
error: post.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
@@ -54,7 +54,7 @@ class PostsController < ApplicationController
|
||||
post = Post.find(params[:id])
|
||||
|
||||
if !current_user.power_user? && current_user.id != post.user_id
|
||||
render json: I18n.t('errors.unauthorized'), status: :unauthorized
|
||||
render json: t('backend.errors.unauthorized'), status: :unauthorized
|
||||
return
|
||||
end
|
||||
|
||||
@@ -83,7 +83,7 @@ class PostsController < ApplicationController
|
||||
render json: post, status: :no_content
|
||||
else
|
||||
render json: {
|
||||
error: I18n.t('errors.post.update', message: post.errors.full_messages)
|
||||
error: post.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
module ApplicationHelper
|
||||
def authenticate_admin
|
||||
unless user_signed_in?
|
||||
flash[:alert] = 'You must be logged in to access this page.'
|
||||
flash[:alert] = t('backend.errors.not_logged_in')
|
||||
redirect_to new_user_session_path
|
||||
return
|
||||
end
|
||||
|
||||
unless current_user.moderator? || current_user.admin?
|
||||
flash[:alert] = 'You do not have the privilegies to access this page.'
|
||||
flash[:alert] = t('backend.errors.not_enough_privileges')
|
||||
redirect_to root_path
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import NewPostForm from './NewPostForm';
|
||||
import Spinner from '../shared/Spinner';
|
||||
@@ -86,7 +87,7 @@ class NewPost extends React.Component<Props, State> {
|
||||
|
||||
if (title === '') {
|
||||
this.setState({
|
||||
error: 'You forgot to enter a title!',
|
||||
error: I18n.t('board.new_post.no_title'),
|
||||
isLoading: false,
|
||||
});
|
||||
return;
|
||||
@@ -109,7 +110,7 @@ class NewPost extends React.Component<Props, State> {
|
||||
|
||||
if (res.status === HttpStatus.Created) {
|
||||
this.setState({
|
||||
success: 'Post published! You will be redirected soon...',
|
||||
success: I18n.t('board.new_post.submit_success'),
|
||||
|
||||
title: '',
|
||||
description: '',
|
||||
@@ -124,7 +125,7 @@ class NewPost extends React.Component<Props, State> {
|
||||
|
||||
} catch (e) {
|
||||
this.setState({
|
||||
error: 'An unknown error occurred, try again.'
|
||||
error: I18n.t('board.new_post.submit_error')
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -151,11 +152,16 @@ class NewPost extends React.Component<Props, State> {
|
||||
onClick={this.toggleForm}
|
||||
className="submitBtn"
|
||||
outline={showForm}>
|
||||
{ showForm ? 'Cancel' : 'Submit feedback' }
|
||||
{
|
||||
showForm ?
|
||||
I18n.t('board.new_post.cancel_button')
|
||||
:
|
||||
I18n.t('board.new_post.submit_button')
|
||||
}
|
||||
</Button>
|
||||
:
|
||||
<a href="/users/sign_in" className="btn btn-dark">
|
||||
Log in / Sign up
|
||||
{I18n.t('board.new_post.login_button')}
|
||||
</a>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import Button from '../shared/Button';
|
||||
|
||||
@@ -20,7 +21,7 @@ const NewPostForm = ({
|
||||
<div className="newPostForm">
|
||||
<form>
|
||||
<div className="form-group">
|
||||
<label htmlFor="postTitle">Title</label>
|
||||
<label htmlFor="postTitle">{I18n.t('board.new_post.title')}</label>
|
||||
<input
|
||||
type="text"
|
||||
value={title}
|
||||
@@ -33,7 +34,7 @@ const NewPostForm = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="postDescription">Description (optional)</label>
|
||||
<label htmlFor="postDescription">{I18n.t('board.new_post.description')}</label>
|
||||
<textarea
|
||||
value={description}
|
||||
onChange={e => handleDescriptionChange(e.target.value)}
|
||||
@@ -44,7 +45,7 @@ const NewPostForm = ({
|
||||
></textarea>
|
||||
</div>
|
||||
<Button onClick={e => handleSubmit(e)} className="submitBtn d-block mx-auto">
|
||||
Submit feedback
|
||||
{I18n.t('board.new_post.submit_button')}
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import I18n from 'i18n-js';
|
||||
import InfiniteScroll from 'react-infinite-scroller';
|
||||
|
||||
import PostListItem from './PostListItem';
|
||||
@@ -64,7 +64,7 @@ const PostList = ({
|
||||
/>
|
||||
))
|
||||
:
|
||||
areLoading ? <p></p> : <CenteredMutedText>There are no posts.</CenteredMutedText>
|
||||
areLoading ? <p></p> : <CenteredMutedText>{I18n.t('board.posts_list.empty')}</CenteredMutedText>
|
||||
}
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import PostStatusListItem from './PostStatusListItem';
|
||||
import Spinner from '../shared/Spinner';
|
||||
@@ -24,7 +25,7 @@ const PostStatusFilter = ({
|
||||
currentFilter,
|
||||
}: Props) => (
|
||||
<div className="postStatusFilterContainer sidebarCard">
|
||||
<BoxTitleText>Filter by status</BoxTitleText>
|
||||
<BoxTitleText>{I18n.t('board.filter_box.title')}</BoxTitleText>
|
||||
{
|
||||
postStatuses.map((postStatus, i) => (
|
||||
<PostStatusListItem
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import { BoxTitleText } from '../shared/CustomTexts';
|
||||
|
||||
@@ -9,7 +10,7 @@ interface Props {
|
||||
|
||||
const SearchFilter = ({ searchQuery, handleChange }: Props) => (
|
||||
<div className="sidebarCard">
|
||||
<BoxTitleText>Search</BoxTitleText>
|
||||
<BoxTitleText>{I18n.t('board.search_box.title')}</BoxTitleText>
|
||||
|
||||
<input
|
||||
type="search"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
import Gravatar from 'react-gravatar';
|
||||
|
||||
import NewComment from './NewComment';
|
||||
@@ -50,12 +51,24 @@ const Comment = ({
|
||||
<div className="commentHeader">
|
||||
<Gravatar email={userEmail} size={28} className="gravatar" />
|
||||
<span className="commentAuthor">{userFullName}</span>
|
||||
{ isPostUpdate ? <span className="postUpdateBadge">Post update</span> : null }
|
||||
{
|
||||
isPostUpdate ?
|
||||
<span className="postUpdateBadge">
|
||||
{I18n.t('post.comments.post_update_badge')}
|
||||
</span>
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
<p className="commentBody">{body}</p>
|
||||
<div className="commentFooter">
|
||||
<a className="commentReplyButton commentLink" onClick={handleToggleCommentReply}>
|
||||
{ replyForm.isOpen ? 'Cancel' : 'Reply' }
|
||||
{
|
||||
replyForm.isOpen ?
|
||||
I18n.t('common.buttons.cancel')
|
||||
:
|
||||
I18n.t('post.comments.reply_button')
|
||||
}
|
||||
</a>
|
||||
{
|
||||
isPowerUser ?
|
||||
@@ -68,14 +81,18 @@ const Comment = ({
|
||||
{ 'Post update: ' + (isPostUpdate ? 'yes' : 'no') }
|
||||
</a>
|
||||
<Separator />
|
||||
<a href={`/admin/comments/${id}/edit`} className="commentLink" data-turbolinks="false">Edit</a>
|
||||
<a href={`/admin/comments/${id}/edit`} className="commentLink" data-turbolinks="false">
|
||||
{I18n.t('common.buttons.edit')}
|
||||
</a>
|
||||
<Separator />
|
||||
<a
|
||||
href={`/admin/comments/${id}`}
|
||||
className="commentLink"
|
||||
data-method="delete"
|
||||
data-confirm="Are you sure?"
|
||||
data-turbolinks="false">Delete</a>
|
||||
data-turbolinks="false">
|
||||
{I18n.t('common.buttons.delete')}
|
||||
</a>
|
||||
|
||||
</React.Fragment>
|
||||
:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import NewComment from './NewComment';
|
||||
import CommentList from './CommentList';
|
||||
@@ -7,6 +8,7 @@ import { DangerText } from '../shared/CustomTexts';
|
||||
|
||||
import IComment from '../../interfaces/IComment';
|
||||
import { ReplyFormState } from '../../reducers/replyFormReducer';
|
||||
import Separator from '../shared/Separator';
|
||||
|
||||
interface Props {
|
||||
postId: number;
|
||||
@@ -106,7 +108,9 @@ class CommentsP extends React.Component<Props> {
|
||||
{ error ? <DangerText>{error}</DangerText> : null }
|
||||
|
||||
<div className="commentsTitle">
|
||||
activity • {comments.length} comment{comments.length === 1 ? '' : 's'}
|
||||
{I18n.t('post.comments.title')}
|
||||
<Separator />
|
||||
{I18n.t('common.comments_number', { count: comments.length })}
|
||||
</div>
|
||||
|
||||
<CommentList
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
import Gravatar from 'react-gravatar';
|
||||
|
||||
import NewCommentUpdateSection from './NewCommentUpdateSection';
|
||||
@@ -50,13 +51,13 @@ const NewComment = ({
|
||||
<textarea
|
||||
value={body}
|
||||
onChange={handleChange}
|
||||
placeholder="Leave a comment"
|
||||
placeholder={I18n.t('post.new_comment.body_placeholder')}
|
||||
className="newCommentBody"
|
||||
/>
|
||||
<Button
|
||||
onClick={() => handleSubmit(body, parentId, postUpdateFlagValue)}
|
||||
className="submitCommentButton">
|
||||
{ isSubmitting ? <Spinner color="light" /> : 'Submit' }
|
||||
{ isSubmitting ? <Spinner color="light" /> : I18n.t('post.new_comment.submit_button') }
|
||||
</Button>
|
||||
</div>
|
||||
{
|
||||
@@ -70,9 +71,12 @@ const NewComment = ({
|
||||
}
|
||||
</React.Fragment>
|
||||
:
|
||||
<a href="/users/sign_in" className="loginInfo">You need to log in to post comments.</a>
|
||||
<a href="/users/sign_in" className="loginInfo">
|
||||
{I18n.t('post.new_comment.not_logged_in')}
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
|
||||
{ error ? <DangerText>{error}</DangerText> : null }
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import { MutedText } from '../shared/CustomTexts';
|
||||
|
||||
interface Props {
|
||||
@@ -19,11 +21,11 @@ const NewCommentUpdateSection = ({
|
||||
checked={postUpdateFlagValue || false}
|
||||
/>
|
||||
|
||||
<label htmlFor="isPostUpdateFlag">Mark as post update</label>
|
||||
<label htmlFor="isPostUpdateFlag">{I18n.t('post.new_comment.is_post_update')}</label>
|
||||
</div>
|
||||
{
|
||||
postUpdateFlagValue ?
|
||||
<MutedText>Users that follow this post will be notified</MutedText>
|
||||
<MutedText>{I18n.t('post.new_comment.user_notification')}</MutedText>
|
||||
:
|
||||
null
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import Button from '../shared/Button';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import Button from '../shared/Button';
|
||||
import { BoxTitleText, SmallMutedText } from '../shared/CustomTexts';
|
||||
|
||||
interface Props {
|
||||
@@ -13,17 +14,17 @@ interface Props {
|
||||
const ActionBox = ({followed, submitFollow, isLoggedIn}: Props) => (
|
||||
<div className="actionBoxContainer">
|
||||
<div className="actionBoxFollow">
|
||||
<BoxTitleText>Actions</BoxTitleText>
|
||||
<BoxTitleText>{I18n.t('post.action_box.title')}</BoxTitleText>
|
||||
<br />
|
||||
<Button onClick={isLoggedIn ? submitFollow : () => location.href = '/users/sign_in'} outline>
|
||||
{ followed ? 'Unfollow post' : 'Follow post' }
|
||||
{ followed ? I18n.t('post.action_box.unfollow_button') : I18n.t('post.action_box.follow_button') }
|
||||
</Button>
|
||||
<br />
|
||||
<SmallMutedText>
|
||||
{ followed ?
|
||||
'you\'re receiving notifications about new updates on this post'
|
||||
I18n.t('post.action_box.following_description')
|
||||
:
|
||||
'you won\'t receive notifications about this post'
|
||||
I18n.t('post.action_box.not_following_description')
|
||||
}
|
||||
</SmallMutedText>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
import Gravatar from 'react-gravatar';
|
||||
|
||||
import ILike from '../../interfaces/ILike';
|
||||
@@ -17,11 +18,13 @@ interface Props {
|
||||
|
||||
const LikeList = ({ likes, areLoading, error}: Props) => (
|
||||
<div className="likeListContainer">
|
||||
<BoxTitleText>Likes</BoxTitleText>
|
||||
<BoxTitleText>{I18n.t('post.likes_box.title')}</BoxTitleText>
|
||||
|
||||
{ areLoading ? <Spinner /> : null }
|
||||
{ error ? <DangerText>{error}</DangerText> : null }
|
||||
|
||||
<div className="likeList">
|
||||
{ likes.length === 0 ? <CenteredMutedText>There are no likes yet.</CenteredMutedText> : null }
|
||||
{ likes.length === 0 ? <CenteredMutedText>{I18n.t('post.likes_box.empty')}</CenteredMutedText> : null }
|
||||
{
|
||||
likes.map((like, i) => (
|
||||
<div className="likeListItem" key={i}>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import IPost from '../../interfaces/IPost';
|
||||
import IPostStatus from '../../interfaces/IPostStatus';
|
||||
@@ -135,7 +136,11 @@ class PostP extends React.Component<Props> {
|
||||
<h2>{post.title}</h2>
|
||||
{
|
||||
isPowerUser && post ?
|
||||
<a href={`/admin/posts/${post.id}`} data-turbolinks="false">Edit</a> : null
|
||||
<a href={`/admin/posts/${post.id}`} data-turbolinks="false">
|
||||
{I18n.t('post.edit_button')}
|
||||
</a>
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import IPostStatus from '../../interfaces/IPostStatus';
|
||||
|
||||
@@ -35,7 +36,7 @@ const PostStatusSelect = ({
|
||||
))}
|
||||
</optgroup>
|
||||
<optgroup label="No post status">
|
||||
<option value={NO_POST_STATUS_VALUE}>None</option>
|
||||
<option value={NO_POST_STATUS_VALUE}>{I18n.t('post.post_status_select.no_post_status')}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
import Gravatar from 'react-gravatar';
|
||||
|
||||
import { BoxTitleText, DangerText, CenteredMutedText, MutedText } from '../shared/CustomTexts';
|
||||
@@ -25,11 +26,18 @@ const PostUpdateList = ({
|
||||
error,
|
||||
}: Props) => (
|
||||
<div className="postUpdateListContainer">
|
||||
<BoxTitleText>Updates</BoxTitleText>
|
||||
<BoxTitleText>{I18n.t('post.updates_box.title')}</BoxTitleText>
|
||||
|
||||
{ areLoading ? <Spinner /> : null }
|
||||
{ error ? <DangerText>{error}</DangerText> : null }
|
||||
|
||||
<div className="postUpdateList">
|
||||
{ postUpdates.length === 0 ? <CenteredMutedText>There are no updates yet.</CenteredMutedText> : null }
|
||||
{
|
||||
postUpdates.length === 0 ?
|
||||
<CenteredMutedText>{I18n.t('post.updates_box.empty')}</CenteredMutedText>
|
||||
:
|
||||
null
|
||||
}
|
||||
{
|
||||
postUpdates.map((postUpdate, i) => (
|
||||
<div className="postUpdateListItem" key={i}>
|
||||
@@ -43,7 +51,7 @@ const PostUpdateList = ({
|
||||
postUpdate.body
|
||||
:
|
||||
<React.Fragment>
|
||||
<i>changed status to</i>
|
||||
<i>{I18n.t('post.updates_box.status_change')}</i>
|
||||
<PostStatusLabel
|
||||
{...postStatuses.find(postStatus => postStatus.id === postUpdate.postStatusId)}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { DescriptionText } from '../../shared/CustomTexts';
|
||||
@@ -82,7 +83,7 @@ class BoardsEditable extends React.Component<Props, State> {
|
||||
</div>
|
||||
|
||||
<div className="boardEditableActions">
|
||||
<a onClick={this.toggleEditMode}>Edit</a>
|
||||
<a onClick={this.toggleEditMode}>{I18n.t('common.buttons.edit')}</a>
|
||||
|
||||
<Separator />
|
||||
|
||||
@@ -90,7 +91,7 @@ class BoardsEditable extends React.Component<Props, State> {
|
||||
onClick={() => handleDelete(id)}
|
||||
data-confirm="Are you sure?"
|
||||
>
|
||||
Delete
|
||||
{I18n.t('common.buttons.delete')}
|
||||
</a>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
@@ -107,7 +108,7 @@ class BoardsEditable extends React.Component<Props, State> {
|
||||
<a
|
||||
className="boardFormCancelButton"
|
||||
onClick={this.toggleEditMode}>
|
||||
Cancel
|
||||
{I18n.t('common.buttons.cancel')}
|
||||
</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import Button from '../../shared/Button';
|
||||
|
||||
@@ -83,7 +84,7 @@ class BoardForm extends React.Component<Props, State> {
|
||||
<div className="boardMandatoryForm">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Board name"
|
||||
placeholder={I18n.t('site_settings.boards.form.name')}
|
||||
value={name}
|
||||
onChange={e => this.onNameChange(e.target.value)}
|
||||
className="form-control"
|
||||
@@ -94,12 +95,17 @@ class BoardForm extends React.Component<Props, State> {
|
||||
className="newBoardButton"
|
||||
disabled={!this.isFormValid()}
|
||||
>
|
||||
{mode === 'create' ? 'Create' : 'Save'}
|
||||
{
|
||||
mode === 'create' ?
|
||||
I18n.t('common.buttons.create')
|
||||
:
|
||||
I18n.t('common.buttons.update')
|
||||
}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
placeholder="Optional board description"
|
||||
placeholder={I18n.t('site_settings.boards.form.description')}
|
||||
value={description}
|
||||
onChange={e => this.onDescriptionChange(e.target.value)}
|
||||
className="form-control"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||
|
||||
@@ -90,7 +91,7 @@ class BoardsSiteSettingsP extends React.Component<Props> {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="content">
|
||||
<h2>Boards</h2>
|
||||
<h2>{I18n.t('site_settings.boards.title')}</h2>
|
||||
|
||||
{
|
||||
boards.items.length > 0 ?
|
||||
@@ -121,12 +122,12 @@ class BoardsSiteSettingsP extends React.Component<Props> {
|
||||
boards.areLoading ?
|
||||
<Spinner />
|
||||
:
|
||||
<CenteredMutedText>There are no boards. Create one below!</CenteredMutedText>
|
||||
<CenteredMutedText>{I18n.t('site_settings.boards.empty')}</CenteredMutedText>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="content">
|
||||
<h2>New</h2>
|
||||
<h2>{I18n.t('site_settings.boards.new')}</h2>
|
||||
|
||||
<BoardForm mode='create' handleSubmit={this.handleSubmit} />
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
|
||||
@@ -74,7 +75,7 @@ class PostStatusEditable extends React.Component<Props, State> {
|
||||
<PostStatusLabel name={name} color={color} />
|
||||
|
||||
<div className="postStatusEditableActions">
|
||||
<a onClick={this.toggleEditMode}>Edit</a>
|
||||
<a onClick={this.toggleEditMode}>{I18n.t('common.buttons.edit')}</a>
|
||||
|
||||
<Separator />
|
||||
|
||||
@@ -82,7 +83,7 @@ class PostStatusEditable extends React.Component<Props, State> {
|
||||
onClick={() => handleDelete(id)}
|
||||
data-confirm="Are you sure?"
|
||||
>
|
||||
Delete
|
||||
{I18n.t('common.buttons.delete')}
|
||||
</a>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
@@ -99,7 +100,7 @@ class PostStatusEditable extends React.Component<Props, State> {
|
||||
<a
|
||||
className="postStatusFormCancelButton"
|
||||
onClick={this.toggleEditMode}>
|
||||
Cancel
|
||||
{I18n.t('common.buttons.cancel')}
|
||||
</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import Button from '../../shared/Button';
|
||||
|
||||
@@ -89,7 +90,7 @@ class PostStatusForm extends React.Component<Props, State> {
|
||||
<div className="postStatusForm">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Post status name"
|
||||
placeholder={I18n.t('site_settings.post_statuses.form.name')}
|
||||
value={name}
|
||||
onChange={e => this.onNameChange(e.target.value)}
|
||||
className="form-control"
|
||||
@@ -107,7 +108,12 @@ class PostStatusForm extends React.Component<Props, State> {
|
||||
className="newPostStatusButton"
|
||||
disabled={!this.isFormValid()}
|
||||
>
|
||||
{mode === 'create' ? 'Create' : 'Save'}
|
||||
{
|
||||
mode === 'create' ?
|
||||
I18n.t('common.buttons.create')
|
||||
:
|
||||
I18n.t('common.buttons.update')
|
||||
}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||
import IPostStatus from '../../../interfaces/IPostStatus';
|
||||
@@ -85,7 +86,7 @@ class PostStatusesSiteSettingsP extends React.Component<Props> {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="content">
|
||||
<h2>Post statuses</h2>
|
||||
<h2>{I18n.t('site_settings.post_statuses.title')}</h2>
|
||||
|
||||
{
|
||||
postStatuses.items.length > 0 ?
|
||||
@@ -116,12 +117,12 @@ class PostStatusesSiteSettingsP extends React.Component<Props> {
|
||||
postStatuses.areLoading ?
|
||||
<Spinner />
|
||||
:
|
||||
<CenteredMutedText>There are no post statuses. Create one below!</CenteredMutedText>
|
||||
<CenteredMutedText>{I18n.t('site_settings.post_statuses.empty')}</CenteredMutedText>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="content">
|
||||
<h2>New</h2>
|
||||
<h2>{I18n.t('site_settings.post_statuses.new')}</h2>
|
||||
|
||||
<PostStatusForm mode='create' handleSubmit={this.handleSubmit} />
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
interface Props {
|
||||
number: number;
|
||||
}
|
||||
|
||||
const CommentsNumber = ({ number }: Props) => (
|
||||
<span className="badge badgeLight">{`${number} comment${number === 1 ? '' : 's'}`}</span>
|
||||
<span className="badge badgeLight">
|
||||
{I18n.t('common.comments_number', { count: number })}
|
||||
</span>
|
||||
);
|
||||
|
||||
export default CommentsNumber;
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
@@ -10,7 +11,7 @@ const PostStatusLabel = ({
|
||||
color,
|
||||
}: Props) => (
|
||||
<span className="badge" style={{backgroundColor: color || 'black', color: 'white'}}>
|
||||
{(name || 'no status').toUpperCase()}
|
||||
{(name || I18n.t('common.no_status')).toUpperCase()}
|
||||
</span>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
import Spinner from './Spinner';
|
||||
|
||||
@@ -14,9 +15,11 @@ const SiteSettingsInfoBox = ({ areUpdating, error }: Props) => (
|
||||
<Spinner />
|
||||
:
|
||||
error ?
|
||||
<span className="error">An error occurred: {JSON.stringify(error)}</span>
|
||||
<span className="error">
|
||||
{I18n.t('site_settings.info_box.error', { message: JSON.stringify(error) })}
|
||||
</span>
|
||||
:
|
||||
<span>Everything up to date</span>
|
||||
<span>{I18n.t('site_settings.info_box.up_to_date')}</span>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import * as React from 'react';
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
const Spinner = ({ color = 'dark' }) => (
|
||||
<div className={`spinner-grow d-block mx-auto text-${color}`} role="status">
|
||||
<span className="sr-only">Loading...</span>
|
||||
<span className="sr-only">{I18n.t('common.loading')}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import I18n from 'i18n-js';
|
||||
|
||||
export const friendlyDate = date => {
|
||||
var now = new Date();
|
||||
var timeStamp = fromRailsStringToJavascriptDate(date);
|
||||
@@ -5,16 +7,16 @@ export const friendlyDate = date => {
|
||||
var secondsPast = (now.getTime() - timeStamp.getTime()) / 1000;
|
||||
|
||||
if (secondsPast < 60) {
|
||||
return 'just now';
|
||||
return I18n.t('common.datetime.now');
|
||||
} else if (secondsPast < 3600) {
|
||||
let minutesPast = Math.round(secondsPast / 60);
|
||||
return minutesPast + ' ' + (minutesPast === 1 ? 'minute' : 'minutes') + ' ago';
|
||||
return I18n.t('common.datetime.minutes', { count: minutesPast });
|
||||
} else if (secondsPast <= 86400) {
|
||||
let hoursPast = Math.round(secondsPast / 3600);
|
||||
return hoursPast + ' ' + (hoursPast === 1 ? 'hour' : 'hours') + ' ago';
|
||||
return I18n.t('common.datetime.hours', { count: hoursPast });
|
||||
} else {
|
||||
let daysPast = Math.round(secondsPast / 86400);
|
||||
return daysPast + ' ' + (daysPast === 1 ? 'day' : 'days') + ' ago';
|
||||
return I18n.t('common.datetime.days', { count: daysPast });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,3 +23,5 @@ require("../images/logo.png")
|
||||
var componentRequireContext = require.context("components", true);
|
||||
var ReactRailsUJS = require("react_ujs");
|
||||
ReactRailsUJS.useContext(componentRequireContext);
|
||||
|
||||
import I18n from 'translations/index.js.erb'
|
||||
3
app/javascript/packs/hello_erb.js.erb
Normal file
3
app/javascript/packs/hello_erb.js.erb
Normal file
@@ -0,0 +1,3 @@
|
||||
<% name = 'Erb' %>
|
||||
|
||||
console.log('Hello world from <%= name %>')
|
||||
4
app/javascript/translations/index.js.erb
Normal file
4
app/javascript/translations/index.js.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
import I18n from "i18n-js"
|
||||
I18n.translations = <%= I18n::JS.filtered_translations.to_json %>
|
||||
I18n.locale = LOCALE
|
||||
export default I18n
|
||||
@@ -1,11 +1,13 @@
|
||||
class UserMailer < ApplicationMailer
|
||||
layout 'user_mailer'
|
||||
|
||||
def notify_post_owner(comment:)
|
||||
@comment = comment
|
||||
@user = comment.post.user
|
||||
|
||||
mail(
|
||||
to: @user.email,
|
||||
subject: "[#{app_name}] New comment on #{comment.post.title}"
|
||||
subject: default_i18n_subject(app_name: app_name, post: comment.post.title)
|
||||
)
|
||||
end
|
||||
|
||||
@@ -15,7 +17,7 @@ class UserMailer < ApplicationMailer
|
||||
|
||||
mail(
|
||||
to: @user.email,
|
||||
subject: "[#{app_name}] New reply on your comment from #{comment.post.title}"
|
||||
subject: default_i18n_subject(app_name: app_name, post: comment.post.title)
|
||||
)
|
||||
end
|
||||
|
||||
@@ -24,7 +26,7 @@ class UserMailer < ApplicationMailer
|
||||
|
||||
mail(
|
||||
to: comment.post.followers.pluck(:email),
|
||||
subject: "[#{app_name}] New update on #{comment.post.title}"
|
||||
subject: default_i18n_subject(app_name: app_name, post: comment.post.title)
|
||||
)
|
||||
end
|
||||
|
||||
@@ -33,7 +35,7 @@ class UserMailer < ApplicationMailer
|
||||
|
||||
mail(
|
||||
to: post.followers.pluck(:email),
|
||||
subject: "[#{app_name}] Status change on post #{post.title}"
|
||||
subject: default_i18n_subject(app_name: app_name, post: post.title)
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
||||
<h2>Resend confirmation instructions</h2>
|
||||
<h2><%= t('common.forms.auth.resend_confirmation_instructions') %></h2>
|
||||
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :email, class: "sr-only" %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email", placeholder: "Email address", required: true, value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email), class: "form-control" %>
|
||||
<%= f.email_field :email,
|
||||
autofocus: true,
|
||||
autocomplete: "email",
|
||||
placeholder: t('common.forms.auth.email'),
|
||||
required: true,
|
||||
value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email),
|
||||
class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Resend confirmation instructions", class: "btn btn-dark btn-block" %>
|
||||
<%= f.submit t('common.forms.auth.resend_confirmation_instructions'), class: "btn btn-dark btn-block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -1,26 +1,35 @@
|
||||
<h2>Change your password</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
|
||||
<h2><%= t('common.forms.auth.change_password') %></h2>
|
||||
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<%= f.hidden_field :reset_password_token %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :password, "New password" %>
|
||||
<%= f.password_field :password, autofocus: true, autocomplete: "new-password", class: "form-control" %>
|
||||
<%= f.label :password, class: "sr-only" %>
|
||||
<%= f.password_field :password,
|
||||
autofocus: true,
|
||||
autocomplete: "new-password",
|
||||
placeholder: t('common.forms.auth.new_password'),
|
||||
class: "form-control" %>
|
||||
|
||||
<% if @minimum_password_length %>
|
||||
<small id="passwordHelp" class="form-text text-muted">
|
||||
(<%= @minimum_password_length %> characters minimum)
|
||||
(<%= t('common.forms.auth.password_help', { count: @minimum_password_length }) %>)
|
||||
</small>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :password_confirmation, "Confirm new password" %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: "form-control" %>
|
||||
<%= f.label :password_confirmation, class: "sr-only" %>
|
||||
<%= f.password_field :password_confirmation,
|
||||
autocomplete: "new-password",
|
||||
placeholder: t('common.forms.auth.new_password_confirmation'),
|
||||
class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Change my password", class: "btn btn-dark btn-primary" %>
|
||||
<%= f.submit t('common.forms.auth.change_password'), class: "btn btn-dark btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
|
||||
<h2>Forgot your password?</h2>
|
||||
<h2><%= t('common.forms.auth.forgot_password') %></h2>
|
||||
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :email, class: "sr-only" %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email", placeholder: "Email address", required: true, class: "form-control" %>
|
||||
<%= f.email_field :email,
|
||||
autofocus: true,
|
||||
autocomplete: "email",
|
||||
placeholder: t('common.forms.auth.email'),
|
||||
required: true,
|
||||
class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Send me reset password instructions", class: "btn btn-dark btn-block" %>
|
||||
<%= f.submit t('common.forms.auth.send_reset_password_instructions'), class: "btn btn-dark btn-block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
|
||||
<h2>Profile settings</h2>
|
||||
<h2><%= t('common.forms.auth.profile_settings') %></h2>
|
||||
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :full_name %>
|
||||
<%= f.label t('common.forms.auth.full_name') %>
|
||||
<%= f.text_field :full_name, autocomplete: "full-name", class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :email %>
|
||||
<%= f.label t('common.forms.auth.email') %>
|
||||
<%= f.email_field :email, autocomplete: "email", class: "form-control" %>
|
||||
<small id="emailGravatarHelp" class="form-text text-muted">
|
||||
the email is <a href="https://gravatar.com" target="_blank">gravatar</a>ized
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :notifications_enabled %>
|
||||
<%= f.label t('common.forms.auth.notifications_enabled') %>
|
||||
<%= f.check_box :notifications_enabled, style: "transform: scale(1.5)" %>
|
||||
<small id="notificationsHelp" class="form-text text-muted">
|
||||
if disabled, you won't receive any notification
|
||||
<%= t('common.forms.auth.notifications_enabled_help') %>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
@@ -29,25 +26,20 @@
|
||||
<% end %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :password %>
|
||||
<%= f.label t('common.forms.auth.password') %>
|
||||
<%= f.password_field :password, autocomplete: "new-password", class: "form-control" %>
|
||||
<% if @minimum_password_length %>
|
||||
<small id="passwordEditHelp" class="form-text text-muted">
|
||||
leave blank if you don't want to change it
|
||||
</small>
|
||||
<small id="passwordHelp" class="form-text text-muted">
|
||||
<%= @minimum_password_length %> characters minimum
|
||||
</small>
|
||||
<% end %>
|
||||
<small id="passwordEditHelp" class="form-text text-muted">
|
||||
leave blank if you don't want to change your password
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :password_confirmation %>
|
||||
<%= f.label t('common.forms.auth.password_confirmation') %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :current_password %>
|
||||
<%= f.label t('common.forms.auth.current_password') %>
|
||||
<%= f.password_field :current_password, autocomplete: "current-password", class: "form-control" %>
|
||||
<small id="currentPasswordHelp" class="form-text text-muted">
|
||||
we need your current password to confirm your changes
|
||||
@@ -55,15 +47,18 @@
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Update profile", class: "btn btn-dark btn-block" %>
|
||||
<%= f.submit t('common.forms.auth.update_profile'), class: "btn btn-dark btn-block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<br />
|
||||
|
||||
<div class="edit_user">
|
||||
<h3>Cancel my account</h3>
|
||||
<p>Unhappy?
|
||||
<%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete, class: "btn btn-danger btn-block" %>
|
||||
</p>
|
||||
<h3><%= t('common.forms.auth.cancel_account') %></h3>
|
||||
|
||||
<%= button_to t('common.forms.auth.cancel_account'),
|
||||
registration_path(resource_name),
|
||||
data: { confirm: "Are you sure?" },
|
||||
method: :delete,
|
||||
class: "btn btn-danger btn-block" %>
|
||||
</div>
|
||||
|
||||
@@ -1,30 +1,44 @@
|
||||
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
|
||||
<h2>Sign up</h2>
|
||||
<h2><%= t('common.forms.auth.sign_up') %></h2>
|
||||
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :full_name, class: "sr-only" %>
|
||||
<%= f.text_field :full_name, autofocus: true, placeholder: "Full name", required: true, class: "form-control" %>
|
||||
<%= f.text_field :full_name,
|
||||
autofocus: true,
|
||||
placeholder: t('common.forms.auth.full_name'),
|
||||
required: true,
|
||||
class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :email, class: "sr-only" %>
|
||||
<%= f.email_field :email, autocomplete: "email", placeholder: "Email address", required: true, class: "form-control" %>
|
||||
<%= f.email_field :email,
|
||||
autocomplete: "email",
|
||||
placeholder: t('common.forms.auth.email'),
|
||||
required: true,
|
||||
class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :password, class: "sr-only" %>
|
||||
<%= f.password_field :password, placeholder: "Password", required: true, class: "form-control" %>
|
||||
<%= f.password_field :password,
|
||||
placeholder: t('common.forms.auth.password'),
|
||||
required: true,
|
||||
class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :password_confirmation, class: "sr-only" %>
|
||||
<%= f.password_field :password_confirmation, placeholder: "Password confirmation", required: true, class: "form-control" %>
|
||||
<%= f.password_field :password_confirmation,
|
||||
placeholder: t('common.forms.auth.password_confirmation'),
|
||||
required: true,
|
||||
class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Sign up", class: "btn btn-dark btn-block" %>
|
||||
<%= f.submit t('common.forms.auth.sign_up'), class: "btn btn-dark btn-block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
|
||||
<h2>Log in</h2>
|
||||
<h2><%= t('common.forms.auth.log_in') %></h2>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :email, class: "sr-only" %>
|
||||
<%= f.email_field :email, autocomplete: "email", placeholder: "Email address", required: true, class: "form-control" %>
|
||||
<%= f.email_field :email,
|
||||
autocomplete: "email",
|
||||
placeholder: t('common.forms.auth.email'),
|
||||
required: true,
|
||||
class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<%= f.label :password, class: "sr-only" %>
|
||||
<%= f.password_field :password, autocomplete: "current-password", placeholder: "Password", required: true, class: "form-control" %>
|
||||
<%= f.password_field :password,
|
||||
autocomplete: "current-password",
|
||||
placeholder: t('common.forms.auth.password'),
|
||||
required: true,
|
||||
class: "form-control" %>
|
||||
</div>
|
||||
|
||||
<% if devise_mapping.rememberable? %>
|
||||
<div class="form-group form-check">
|
||||
<%= f.check_box :remember_me, class: "form-check-input" %>
|
||||
<%= f.label :remember_me, class: "form-check-label" %>
|
||||
<%= f.label t('common.forms.auth.remember_me'), class: "form-check-label" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Log in", class: "btn btn-dark btn-block" %>
|
||||
<%= f.submit t('common.forms.auth.log_in'), class: "btn btn-dark btn-block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<div class="deviseLinks">
|
||||
<%- if controller_name != 'sessions' %>
|
||||
<%= link_to "Log in", new_session_path(resource_name) %>
|
||||
<%= link_to t('common.forms.auth.log_in'), new_session_path(resource_name) %>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
||||
<%= link_to "Sign up", new_registration_path(resource_name) %>
|
||||
<%= link_to t('common.forms.auth.sign_up'), new_registration_path(resource_name) %>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
|
||||
<%= link_to "Forgot your password?", new_password_path(resource_name) %>
|
||||
<%= link_to t('common.forms.auth.forgot_password'), new_password_path(resource_name) %>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
||||
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
|
||||
<%= link_to t('common.forms.auth.confirmation_instructions_not_received'), new_confirmation_path(resource_name) %>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
||||
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
|
||||
<%= link_to t('common.forms.auth.unlock_instructions_not_received'), new_unlock_path(resource_name) %>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.omniauthable? %>
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<h2>Resend unlock instructions</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
|
||||
<h2><%= t('common.forms.auth.resend_unlock_instructions') %></h2>
|
||||
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :email %><br />
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
|
||||
<%= f.label :email, class: "sr-only" %><br />
|
||||
<%= f.email_field :email,
|
||||
autofocus: true,
|
||||
autocomplete: "email"
|
||||
placeholder: t('common.forms.auth.email') %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Resend unlock instructions", class: "btn btn-dark btn-block" %>
|
||||
<%= f.submit t('common.forms.auth.resend_unlock_instructions'), class: "btn btn-dark btn-block" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -26,18 +26,18 @@
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<% if current_user.power_user? %>
|
||||
<%= link_to 'Site settings', site_settings_boards_path, class: 'dropdown-item' %>
|
||||
<%= link_to 'Admin Panel', admin_root_path, class: 'dropdown-item', 'data-turbolinks': 'false' %>
|
||||
<%= link_to t('header.menu.site_settings'), site_settings_boards_path, class: 'dropdown-item' %>
|
||||
<%= link_to t('header.menu.admin_panel'), admin_root_path, class: 'dropdown-item', 'data-turbolinks': 'false' %>
|
||||
<div class="dropdown-divider"></div>
|
||||
<% end %>
|
||||
<%= link_to 'Profile settings', edit_user_registration_path, class: 'dropdown-item' %>
|
||||
<%= link_to t('header.menu.profile_settings'), edit_user_registration_path, class: 'dropdown-item' %>
|
||||
<div class="dropdown-divider"></div>
|
||||
<%= link_to 'Sign out', destroy_user_session_path, method: :delete, class: 'dropdown-item' %>
|
||||
<%= link_to t('header.menu.sign_out'), destroy_user_session_path, method: :delete, class: 'dropdown-item' %>
|
||||
</div>
|
||||
</li>
|
||||
<% else %>
|
||||
<li class="nav-item">
|
||||
<%= link_to 'Log in / Sign up', new_user_session_path, class: 'nav-link' %>
|
||||
<%= link_to t('header.log_in'), new_user_session_path, class: 'nav-link' %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
6
app/views/layouts/_set_js_locale.html.erb
Normal file
6
app/views/layouts/_set_js_locale.html.erb
Normal file
@@ -0,0 +1,6 @@
|
||||
<script type="text/javascript">
|
||||
// Used to set I18n-js locale to Rails locale
|
||||
// Variable used in javascript/translations/index.js.erb
|
||||
|
||||
var LOCALE = "<%= I18n.locale %>";
|
||||
</script>
|
||||
@@ -8,6 +8,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="turbolinks-cache-control" content="no-cache">
|
||||
|
||||
<%= render 'layouts/set_js_locale' %>
|
||||
|
||||
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
|
||||
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
|
||||
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<style>
|
||||
/* Email styles need to be inline */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%= yield %>
|
||||
<div><%= yield %></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
17
app/views/layouts/user_mailer.html.erb
Normal file
17
app/views/layouts/user_mailer.html.erb
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<p><%= t('user_mailer.opening_greeting') %></p>
|
||||
|
||||
<div><%= yield %></div>
|
||||
|
||||
<p><%= t('user_mailer.closing_greeting') %></p>
|
||||
|
||||
<footer>
|
||||
<%= link_to(t('user_mailer.unsubscribe'), edit_user_registration_url) %>.
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
1
app/views/layouts/user_mailer.text.erb
Normal file
1
app/views/layouts/user_mailer.text.erb
Normal file
@@ -0,0 +1 @@
|
||||
<%= yield %>
|
||||
@@ -1,9 +1,9 @@
|
||||
<div class="sidebar">
|
||||
<div class="sidebarCard">
|
||||
<span class="boxTitleText">Site Settings</span>
|
||||
<span class="boxTitleText"><%= t('site_settings.menu.title') %></span>
|
||||
<div class="verticalNavigation" role="tablist" aria-orientation="vertical">
|
||||
<%= render 'menu_link', label: 'Boards', path: site_settings_boards_path %>
|
||||
<%= render 'menu_link', label: 'Post statuses', path: site_settings_post_statuses_path %>
|
||||
<%= render 'menu_link', label: t('site_settings.menu.boards'), path: site_settings_boards_path %>
|
||||
<%= render 'menu_link', label: t('site_settings.menu.post_statuses'), path: site_settings_post_statuses_path %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<h2>Roadmap</h2>
|
||||
<h2><%= t('roadmap.title') %></h2>
|
||||
|
||||
<%=
|
||||
react_component(
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content='text/html; charset=utf-8' http-equiv='content-type' />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello, <%= @user.full_name %></h1>
|
||||
<p>
|
||||
There is a new reply by <b><%= @comment.user.full_name %></b> on your comment from post <b><%= @comment.post.title %></b>:
|
||||
</p>
|
||||
<p>
|
||||
<i><%= @comment.body %></i>
|
||||
</p>
|
||||
<p>
|
||||
<%= link_to "Click here", post_url(@comment.post) %> to have your say!
|
||||
</p>
|
||||
<p>
|
||||
Have a great day!
|
||||
</p>
|
||||
</body>
|
||||
<footer>
|
||||
Annoyed? You can <%= link_to("turn off notifications here", edit_user_registration_url) %>.
|
||||
</footer>
|
||||
</html>
|
||||
<p>
|
||||
<%= t('user_mailer.notify_comment_owner.body', { user: @comment.user.full_name, post: @comment.post.title }) %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<i><%= @comment.body %></i>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= link_to t('user_mailer.learn_more'), post_url(@comment.post) %>
|
||||
</p>
|
||||
|
||||
@@ -1,24 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content='text/html; charset=utf-8' http-equiv='content-type' />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello!</h1>
|
||||
<p>
|
||||
The post you're following <b><%= @post.title %></b> has a new status:
|
||||
<span style='background-color: <%= @post.post_status.color %>; color: white;'%>>
|
||||
<%= @post.post_status.name %>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<%= link_to "Click here", post_url(@post) %> to learn more!
|
||||
</p>
|
||||
<p>
|
||||
Have a great day!
|
||||
</p>
|
||||
</body>
|
||||
<footer>
|
||||
Annoyed? You can <%= link_to("turn off notifications here", edit_user_registration_url) %>.
|
||||
</footer>
|
||||
</html>
|
||||
<p>
|
||||
<%= I18n.t('user_mailer.notify_followers_of_post_status_change.body', { post: @post }) %>
|
||||
<span style='background-color: <%= @post.post_status.color %>; color: white;'%>>
|
||||
<%= @post.post_status.name %>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= link_to I18n.t('user_mailer.learn_more'), post_url(@post) %>
|
||||
</p>
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content='text/html; charset=utf-8' http-equiv='content-type' />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello!</h1>
|
||||
<p>
|
||||
There is a new update on the post you're following <b><%= @comment.post.title %></b>:
|
||||
</p>
|
||||
<p>
|
||||
<i><%= @comment.body %></i>
|
||||
</p>
|
||||
<p>
|
||||
<%= link_to "Click here", post_url(@comment.post) %> to have your say!
|
||||
</p>
|
||||
<p>
|
||||
Have a great day!
|
||||
</p>
|
||||
</body>
|
||||
<footer>
|
||||
Annoyed? You can <%= link_to("turn off notifications here", edit_user_registration_url) %>.
|
||||
</footer>
|
||||
</html>
|
||||
<p>
|
||||
<%= I18n.t('user_mailer.notify_followers_of_post_update.body', { user: @comment.user.full_name, post: @comment.post.title }) %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<i><%= @comment.body %></i>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= link_to I18n.t('user_mailer.learn_more'), post_url(@comment.post) %>
|
||||
</p>
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta content='text/html; charset=utf-8' http-equiv='content-type' />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello, <%= @user.full_name %></h1>
|
||||
<p>
|
||||
There is a new comment by <b><%= @comment.user.full_name %></b> on your post <b><%= @comment.post.title %></b>:
|
||||
</p>
|
||||
<p>
|
||||
<i><%= @comment.body %></i>
|
||||
</p>
|
||||
<p>
|
||||
<%= link_to "Click here", post_url(@comment.post) %> to have your say!
|
||||
</p>
|
||||
<p>
|
||||
Have a great day!
|
||||
</p>
|
||||
</body>
|
||||
<footer>
|
||||
Annoyed? You can <%= link_to("turn off notifications here", edit_user_registration_url) %>.
|
||||
</footer>
|
||||
</html>
|
||||
<p>
|
||||
<%= t('user_mailer.notify_post_owner.body', { user: @comment.user.full_name, post: @comment.post.title }) %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<i><%= @comment.body %></i>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= link_to t('user_mailer.learn_more'), post_url(@comment.post) %>
|
||||
</p>
|
||||
|
||||
5
config/initializers/locale.rb
Normal file
5
config/initializers/locale.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
# Configure I18n to look at subfolders too
|
||||
I18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.yml')]
|
||||
|
||||
I18n.available_locales = [:en, :it]
|
||||
I18n.default_locale = :en
|
||||
43
config/locales/activerecord/activerecord.it.yml
Normal file
43
config/locales/activerecord/activerecord.it.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
it:
|
||||
activerecord:
|
||||
attributes:
|
||||
board:
|
||||
name: 'Nome'
|
||||
description: 'Descrizione'
|
||||
order: 'Ordine'
|
||||
comment:
|
||||
body: 'Corpo'
|
||||
is_post_update: 'Aggiornamento post'
|
||||
user_id: 'Autore'
|
||||
post_id: 'Post'
|
||||
parent_id: 'Commento padre'
|
||||
follow:
|
||||
user_id: 'Utente'
|
||||
post_id: 'Post'
|
||||
like:
|
||||
user_id: 'Utente'
|
||||
post_id: 'Post'
|
||||
post_status:
|
||||
name: 'Nome'
|
||||
color: 'Colore'
|
||||
order: 'Ordine'
|
||||
show_in_roadmap: 'Mostra nella roadmap'
|
||||
post:
|
||||
title: 'Titolo'
|
||||
description: 'Descrizione'
|
||||
board_id: 'Bacheca del post'
|
||||
user_id: 'Autore del post'
|
||||
post_status_id: 'Stato del post'
|
||||
user:
|
||||
email: 'E-mail'
|
||||
full_name: 'Nome e cognome'
|
||||
role: 'Ruolo'
|
||||
notifications_enabled: 'Notifiche abilitate'
|
||||
errors:
|
||||
messages:
|
||||
invalid: 'è invalido'
|
||||
required: 'è obbligatorio'
|
||||
blank: 'non può essere vuoto'
|
||||
taken: 'è già in uso'
|
||||
too_short: 'è troppo corto (almeno %{count} caratteri)'
|
||||
too_long: 'è troppo lungo (massimo ${count} caratteri)'
|
||||
66
config/locales/devise/devise.it.yml
Normal file
66
config/locales/devise/devise.it.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
# Italian translation for Devise 4.2
|
||||
# Date: 2016-08-01
|
||||
# Author: epistrephein, iwan
|
||||
# Note: Thanks to xpepper (https://gist.github.com/xpepper/8052632)
|
||||
# Additional translations at https://github.com/plataformatec/devise/wiki/I18n
|
||||
|
||||
it:
|
||||
devise:
|
||||
confirmations:
|
||||
confirmed: "Il tuo account è stato correttamente confermato."
|
||||
send_instructions: "Entro qualche minuto riceverai un messaggio email con le istruzioni per confermare il tuo account."
|
||||
send_paranoid_instructions: "Se il tuo indirizzo email esiste nel nostro database, entro qualche minuto riceverai un messaggio email con le istruzioni per confermare il tuo account."
|
||||
failure:
|
||||
already_authenticated: "Hai già effettuato l'accesso."
|
||||
inactive: "Il tuo account non è ancora stato attivato."
|
||||
invalid: "%{authentication_keys} o password non validi."
|
||||
locked: "Il tuo account è bloccato."
|
||||
last_attempt: "Hai un altro tentativo prima che il tuo account venga bloccato."
|
||||
not_found_in_database: "%{authentication_keys} o password non validi."
|
||||
timeout: "La tua sessione è scaduta, accedi nuovamente per continuare."
|
||||
unauthenticated: "Devi accedere o registrarti per continuare."
|
||||
unconfirmed: "Devi confermare il tuo indirizzo email per continuare."
|
||||
mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Istruzioni per la conferma"
|
||||
reset_password_instructions:
|
||||
subject: "Istruzioni per reimpostare la password"
|
||||
unlock_instructions:
|
||||
subject: "Istruzioni per sbloccare l'account"
|
||||
password_change:
|
||||
subject: "Password reimpostata"
|
||||
omniauth_callbacks:
|
||||
failure: 'Non è stato possibile autenticarti come %{kind} perché "%{reason}".'
|
||||
success: "Autenticato con successo dall'account %{kind}."
|
||||
passwords:
|
||||
no_token: "Non è possibile accedere a questa pagina se non provieni da una e-mail di ripristino della password. Se provieni da una e-mail di ripristino della password, assicurarti di utilizzare l'URL completo."
|
||||
send_instructions: "Entro qualche minuto riceverai un messaggio email con le istruzioni per reimpostare la tua password."
|
||||
send_paranoid_instructions: "Se il tuo indirizzo email esiste nel nostro database, entro qualche minuto riceverai un messaggio email con le istruzioni per ripristinare la password."
|
||||
updated: "La tua password è stata cambiata correttamente. Ora sei collegato."
|
||||
updated_not_active: "La tua password è stata cambiata correttamente."
|
||||
registrations:
|
||||
destroyed: "Arrivederci! Il tuo account è stato cancellato. Speriamo di rivederti presto."
|
||||
signed_up: "Benvenuto! Ti sei registrato correttamente."
|
||||
signed_up_but_inactive: "Ti sei registrato correttamente. Tuttavia non puoi effettuare l'accesso perché il tuo account non è stato ancora attivato."
|
||||
signed_up_but_locked: "Ti sei registrato correttamente. Tuttavia non puoi effettuare l'accesso perché il tuo account è bloccato."
|
||||
signed_up_but_unconfirmed: "Ti sei registrato correttamente. Un messaggio con il link per confermare il tuo account è stato inviato al tuo indirizzo email."
|
||||
update_needs_confirmation: "Il tuo account è stato aggiornato, tuttavia è necessario verificare il tuo nuovo indirizzo email. Entro qualche minuto riceverai un messaggio email con le istruzioni per confermare il tuo nuovo indirizzo email."
|
||||
updated: "Il tuo account è stato aggiornato."
|
||||
sessions:
|
||||
signed_in: "Accesso effettuato con successo."
|
||||
signed_out: "Sei uscito correttamente."
|
||||
already_signed_out: "Sei uscito correttamente."
|
||||
unlocks:
|
||||
send_instructions: "Entro qualche minuto riceverai un messaggio email con le istruzioni per sbloccare il tuo account."
|
||||
send_paranoid_instructions: "Se il tuo indirizzo email esiste nel nostro database, entro qualche minuto riceverai un messaggio email con le istruzioni per sbloccare il tuo account."
|
||||
unlocked: "Il tuo account è stato correttamente sbloccato. Accedi per continuare."
|
||||
errors:
|
||||
messages:
|
||||
already_confirmed: "è stato già confermato, prova ad effettuare un nuovo accesso"
|
||||
confirmation_period_expired: "deve essere confermato entro %{period}, si prega di richiederne uno nuovo"
|
||||
expired: "è scaduto, si prega di richiederne uno nuovo"
|
||||
not_found: "non trovato"
|
||||
not_locked: "non era bloccato"
|
||||
not_saved:
|
||||
one: "Un errore ha impedito di salvare questo %{resource}:"
|
||||
other: "%{count} errori hanno impedito di salvare questo %{resource}:"
|
||||
@@ -1,11 +1,148 @@
|
||||
en:
|
||||
errors:
|
||||
unauthorized: 'You are not authorized'
|
||||
post:
|
||||
create: 'Post create error: %{message}'
|
||||
update: 'Post update error: %{message}'
|
||||
like:
|
||||
create: 'Like create error: %{message}'
|
||||
comment:
|
||||
create: 'Comment create error: %{message}'
|
||||
update: 'Comment update error: %{message}'
|
||||
common:
|
||||
forms:
|
||||
auth:
|
||||
email: 'Email address'
|
||||
full_name: 'Full name'
|
||||
password: 'Password'
|
||||
password_confirmation: 'Password confirmation'
|
||||
new_password: 'New password'
|
||||
new_password_confirmation: 'New password confirmation'
|
||||
current_password: 'Current password'
|
||||
notifications_enabled: 'Notifications enabled'
|
||||
notifications_enabled_help: "if disabled, you won't receive any notification"
|
||||
remember_me: 'Remember me'
|
||||
log_in: 'Log in'
|
||||
sign_up: 'Sign up'
|
||||
profile_settings: 'Profile settings'
|
||||
update_profile: 'Update profile'
|
||||
cancel_account: 'Cancel account'
|
||||
forgot_password: 'Forgot your password?'
|
||||
confirmation_instructions_not_received: "Didn't receive confirmation instructions?"
|
||||
unlock_instructions_not_received: "Didn't receive unlock instructions?"
|
||||
send_reset_password_instructions: 'Send me reset password instructions'
|
||||
resend_confirmation_instructions: 'Resend confirmation instructions'
|
||||
resend_unlock_instructions: 'Resend unlock instructions'
|
||||
change_password: 'Change password'
|
||||
password_help: '%{count} characters minimum'
|
||||
comments_number:
|
||||
one: '1 comment'
|
||||
other: '%{count} comments'
|
||||
no_status: 'No status'
|
||||
loading: 'Loading...'
|
||||
buttons:
|
||||
edit: 'Edit'
|
||||
delete: 'Delete'
|
||||
cancel: 'Cancel'
|
||||
create: 'Create'
|
||||
update: 'Save'
|
||||
datetime:
|
||||
now: 'just now'
|
||||
minutes:
|
||||
one: '1 minute ago'
|
||||
other: '%{count} minutes ago'
|
||||
hours:
|
||||
one: '1 hour ago'
|
||||
other: '%{count} hours ago'
|
||||
days:
|
||||
one: '1 day ago'
|
||||
other: '%{count} days ago'
|
||||
header:
|
||||
menu:
|
||||
site_settings: 'Site settings'
|
||||
admin_panel: 'Admin panel (deprecated)'
|
||||
profile_settings: 'Profile settings'
|
||||
sign_out: 'Sign out'
|
||||
log_in: 'Log in / Sign up'
|
||||
roadmap:
|
||||
title: 'Roadmap'
|
||||
board:
|
||||
new_post:
|
||||
submit_button: 'Submit feedback'
|
||||
cancel_button: 'Cancel'
|
||||
login_button: 'Log in / Sign up'
|
||||
title: 'Title'
|
||||
description: 'Description (optional)'
|
||||
no_title: 'Title field is mandatory'
|
||||
submit_success: 'Feedback published! You will be redirected soon...'
|
||||
submit_error: 'An unknown error occurred, try again'
|
||||
search_box:
|
||||
title: 'Search'
|
||||
filter_box:
|
||||
title: 'Filter by status'
|
||||
posts_list:
|
||||
empty: 'There are no posts'
|
||||
post:
|
||||
edit_button: 'Edit'
|
||||
post_status_select:
|
||||
no_post_status: 'None'
|
||||
updates_box:
|
||||
title: 'Updates'
|
||||
empty: 'There are no updates yet'
|
||||
status_change: 'changed status to'
|
||||
likes_box:
|
||||
title: 'Likes'
|
||||
empty: 'There are no likes yet'
|
||||
action_box:
|
||||
title: 'Actions'
|
||||
follow_button: 'Follow'
|
||||
unfollow_button: 'Unfollow'
|
||||
following_description: "you're receiving notifications about new updates on this post"
|
||||
not_following_description: "you won't receive notifications about this post"
|
||||
comments:
|
||||
title: 'Activity'
|
||||
post_update_badge: 'Update'
|
||||
reply_button: 'Reply'
|
||||
new_comment:
|
||||
body_placeholder: 'Leave a comment'
|
||||
submit_button: 'Submit'
|
||||
is_post_update: 'Mark as update'
|
||||
user_notification: 'Users that follow this post will be notified'
|
||||
not_logged_in: 'You need to log in to post comments'
|
||||
site_settings:
|
||||
menu:
|
||||
title: 'Site settings'
|
||||
boards: 'Boards'
|
||||
post_statuses: 'Statuses'
|
||||
info_box:
|
||||
up_to_date: 'All changes saved'
|
||||
error: 'An error occurred: %{message}'
|
||||
boards:
|
||||
title: 'Boards'
|
||||
empty: 'There are no boards. Create one below!'
|
||||
new: 'New'
|
||||
form:
|
||||
name: 'Board name'
|
||||
description: 'Board description (optional)'
|
||||
post_statuses:
|
||||
title: 'Statuses'
|
||||
empty: 'There are no statuses. Create one below!'
|
||||
new: 'New'
|
||||
form:
|
||||
name: 'Status name'
|
||||
user_mailer:
|
||||
opening_greeting: 'Hello!'
|
||||
closing_greeting: 'Have a great day!'
|
||||
learn_more: 'Click here to learn more'
|
||||
unsubscribe: 'Annoyed? You can turn off notifications here'
|
||||
notify_post_owner:
|
||||
subject: '[%{app_name}] New comment on %{post}'
|
||||
body: 'There is a new comment by %{user} on your post %{post}'
|
||||
notify_comment_owner:
|
||||
subject: '[%{app_name}] New reply on your comment from %{post}'
|
||||
body: 'There is a new reply by %{user} on your comment from post %{post}'
|
||||
notify_followers_of_post_update:
|
||||
subject: '[%{app_name}] New update for post %{post}'
|
||||
body: "There is a new update on the post you're following %{post}"
|
||||
notify_followers_of_post_status_change:
|
||||
subject: '[%{app_name}] Status change on post %{post}'
|
||||
body: "The post you're following %{post} has a new status"
|
||||
backend:
|
||||
errors:
|
||||
unauthorized: 'You are not authorized'
|
||||
not_logged_in: 'You must be logged in to access this page'
|
||||
not_enough_privileges: 'You do not have the privilegies to access this page'
|
||||
board:
|
||||
update_order: 'There was an error in reordering boards'
|
||||
post_status:
|
||||
update_order: 'There was an error in reordering statuses'
|
||||
148
config/locales/it.yml
Normal file
148
config/locales/it.yml
Normal file
@@ -0,0 +1,148 @@
|
||||
it:
|
||||
common:
|
||||
forms:
|
||||
auth:
|
||||
email: 'Indirizzo email'
|
||||
full_name: 'Nome e cognome'
|
||||
password: 'Password'
|
||||
password_confirmation: 'Conferma password'
|
||||
new_password: 'Nuova password'
|
||||
new_password_confirmation: 'Conferma nuova password'
|
||||
current_password: 'Password corrente'
|
||||
notifications_enabled: 'Notifiche abilitate'
|
||||
notifications_enabled_help: "se disabilitato, non riceverai alcuna notifica"
|
||||
remember_me: 'Ricordami'
|
||||
log_in: 'Accedi'
|
||||
sign_up: 'Registrati'
|
||||
profile_settings: 'Impostazioni profilo'
|
||||
update_profile: 'Aggiorna profilo'
|
||||
cancel_account: 'Cancella account'
|
||||
forgot_password: 'Password dimenticata?'
|
||||
confirmation_instructions_not_received: 'Non hai ricevuto le istruzioni di conferma?'
|
||||
unlock_instructions_not_received: 'Non hai ricevuto le istruzioni di sblocco?'
|
||||
send_reset_password_instructions: 'Invia istruzioni per reset password'
|
||||
resend_confirmation_instructions: 'Invia istruzioni di conferma'
|
||||
resend_unlock_instructions: 'Invia istruzioni di sblocco'
|
||||
change_password: 'Cambia password'
|
||||
password_help: '%{count} caratteri minimo'
|
||||
comments_number:
|
||||
one: '1 commento'
|
||||
other: '%{count} commenti'
|
||||
no_status: 'Nessuno stato'
|
||||
loading: 'Caricamento...'
|
||||
buttons:
|
||||
edit: 'Modifica'
|
||||
delete: 'Elimina'
|
||||
cancel: 'Annulla'
|
||||
create: 'Crea'
|
||||
update: 'Salva'
|
||||
datetime:
|
||||
now: 'adesso'
|
||||
minutes:
|
||||
one: '1 minuto fa'
|
||||
other: '%{count} minuti fa'
|
||||
hours:
|
||||
one: '1 ora fa'
|
||||
other: '%{count} ore fa'
|
||||
days:
|
||||
one: '1 giorno fa'
|
||||
other: '%{count} giorni fa'
|
||||
header:
|
||||
menu:
|
||||
site_settings: 'Impostazioni sito'
|
||||
admin_panel: 'Admin panel (deprecato)'
|
||||
profile_settings: 'Impostazioni profilo'
|
||||
sign_out: 'Esci'
|
||||
log_in: 'Accedi / Registrati'
|
||||
roadmap:
|
||||
title: 'Roadmap'
|
||||
board:
|
||||
new_post:
|
||||
submit_button: 'Invia feedback'
|
||||
cancel_button: 'Annulla'
|
||||
login_button: 'Accedi / Registrati'
|
||||
title: 'Titolo'
|
||||
description: 'Descrizione (opzionale)'
|
||||
no_title: 'Il campo titolo è obbligatorio'
|
||||
submit_success: 'Feedback pubblicato! Sarai reindirizzato a breve...'
|
||||
submit_error: 'Si è verificato un errore sconosciuto, riprova'
|
||||
search_box:
|
||||
title: 'Cerca'
|
||||
filter_box:
|
||||
title: 'Filtra per stato'
|
||||
posts_list:
|
||||
empty: 'Non ci sono post'
|
||||
post:
|
||||
edit_button: 'Modifica'
|
||||
post_status_select:
|
||||
no_post_status: 'Nessuno'
|
||||
updates_box:
|
||||
title: 'Aggiornamenti'
|
||||
empty: 'Non ci sono aggiornamenti per ora'
|
||||
status_change: 'stato cambiato in'
|
||||
likes_box:
|
||||
title: 'Mi piace'
|
||||
empty: 'Non ci sono mi piace per ora'
|
||||
action_box:
|
||||
title: 'Azioni'
|
||||
follow_button: 'Segui'
|
||||
unfollow_button: 'Non seguire più'
|
||||
following_description: 'riceverai notifiche sugli aggiornamenti di questo post'
|
||||
not_following_description: 'non riceverai alcuna notifica riguardo questo post'
|
||||
comments:
|
||||
title: 'Attività'
|
||||
post_update_badge: 'Aggiornamento'
|
||||
reply_button: 'Rispondi'
|
||||
new_comment:
|
||||
body_placeholder: 'Lascia un commento'
|
||||
submit_button: 'Invia'
|
||||
is_post_update: 'Contrassegna come aggiornamento'
|
||||
user_notification: 'Gli utenti che seguono questo post saranno notificati'
|
||||
not_logged_in: 'Devi effettuare il log in per commentare'
|
||||
site_settings:
|
||||
menu:
|
||||
title: 'Impostazioni sito'
|
||||
boards: 'Bacheche'
|
||||
post_statuses: 'Stati'
|
||||
info_box:
|
||||
up_to_date: 'Tutte le modifiche sono state salvate'
|
||||
error: 'Si è verificato un errore: %{message}'
|
||||
boards:
|
||||
title: 'Bacheche'
|
||||
empty: 'Non ci sono bacheche. Creane una qua sotto!'
|
||||
new: 'Nuova'
|
||||
form:
|
||||
name: 'Nome bacheca'
|
||||
description: 'Descrizione bacheca (opzionale)'
|
||||
post_statuses:
|
||||
title: 'Stati'
|
||||
empty: 'Non ci sono stati. Creane uno qua sotto!'
|
||||
new: 'Nuovo'
|
||||
form:
|
||||
name: 'Nome stato'
|
||||
user_mailer:
|
||||
opening_greeting: 'Ciao!'
|
||||
closing_greeting: 'Buona giornata!'
|
||||
learn_more: 'Clicca qui per saperne di più'
|
||||
unsubscribe: 'Non vuoi più ricevere notifiche? Clicca qui'
|
||||
notify_post_owner:
|
||||
subject: '[%{app_name}] Nuovo commento al tuo post %{post}'
|
||||
body: '%{user} ha commentato il tuo post %{post}'
|
||||
notify_comment_owner:
|
||||
subject: '[%{app_name}] Risposta al tuo commento nel post %{post}'
|
||||
body: '%{user} ha risposto al tuo commento nel post %{post}'
|
||||
notify_followers_of_post_update:
|
||||
subject: '[%{app_name}] Nuovo aggiornamento per il post %{post}'
|
||||
body: "There is a new update on the post you're following %{post}"
|
||||
notify_followers_of_post_status_change:
|
||||
subject: '[%{app_name}] Aggiornamento stato per il post %{post}'
|
||||
body: "Il post che segui %{post} ha un nuovo stato"
|
||||
backend:
|
||||
errors:
|
||||
unauthorized: 'Non sei autorizzato'
|
||||
not_logged_in: "Devi effettuare l'accesso per visualizzare questa pagina"
|
||||
not_enough_privileges: 'Non hai i privilegi necessari per visualizzare questa pagina'
|
||||
board:
|
||||
update_order: 'Si è verificato un errore durante il riordinamento delle bacheche'
|
||||
post_status:
|
||||
update_order: 'Si è verificato un errore durante il riordinamento degli stati'
|
||||
@@ -1,4 +1,5 @@
|
||||
const { environment } = require('@rails/webpacker')
|
||||
const erb = require('./loaders/erb')
|
||||
const typescript = require('./loaders/typescript')
|
||||
const webpack = require('webpack')
|
||||
|
||||
@@ -12,4 +13,5 @@ environment.plugins.append(
|
||||
})
|
||||
)
|
||||
|
||||
environment.loaders.prepend('erb', erb)
|
||||
module.exports = environment
|
||||
|
||||
11
config/webpack/loaders/erb.js
Normal file
11
config/webpack/loaders/erb.js
Normal file
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
test: /\.erb$/,
|
||||
enforce: 'pre',
|
||||
exclude: /node_modules/,
|
||||
use: [{
|
||||
loader: 'rails-erb-loader',
|
||||
options: {
|
||||
runner: (/^win/.test(process.platform) ? 'ruby ' : '') + 'bin/rails runner'
|
||||
}
|
||||
}]
|
||||
}
|
||||
@@ -34,6 +34,7 @@ default: &default
|
||||
- .woff2
|
||||
|
||||
extensions:
|
||||
- .erb
|
||||
- .tsx
|
||||
- .ts
|
||||
- .jsx
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
"@types/react-dom": "^16.9.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
||||
"bootstrap": "4.3.1",
|
||||
"i18n-js": "^3.9.2",
|
||||
"jquery": "^3.5.1",
|
||||
"popper.js": "^1.15.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"rails-erb-loader": "^5.5.2",
|
||||
"react": "^16.9.0",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-dom": "^16.9.0",
|
||||
|
||||
@@ -8,7 +8,6 @@ RSpec.describe UserMailer, type: :mailer do
|
||||
let(:mail) { UserMailer.notify_post_owner(comment: comment) }
|
||||
|
||||
it "renders the headers" do
|
||||
expect(mail.subject).to eq("[#{ENV.fetch('APP_NAME')}] New comment on #{post.title}")
|
||||
expect(mail.to).to eq(["notified@example.com"])
|
||||
expect(mail.from).to eq(["notifications@example.com"])
|
||||
end
|
||||
|
||||
18
yarn.lock
18
yarn.lock
@@ -3474,6 +3474,11 @@ https-browserify@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||
|
||||
i18n-js@^3.9.2:
|
||||
version "3.9.2"
|
||||
resolved "https://registry.yarnpkg.com/i18n-js/-/i18n-js-3.9.2.tgz#4a015dcfabd4c9fc73115fc2d02d2627e4c15ca5"
|
||||
integrity sha512-+Gm8h5HL0emzKhRx2avMKX+nKiVPXeaOZm7Euf2/pbbFcLQoJ3zZYiUykAzoRasijCoWos2Kl1tslmScTgAQKw==
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
@@ -4124,6 +4129,11 @@ lodash._reinterpolate@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
||||
integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
|
||||
|
||||
lodash.defaults@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
|
||||
integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
|
||||
|
||||
lodash.get@^4.0:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
@@ -5982,6 +5992,14 @@ raf-schd@^4.0.2:
|
||||
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
|
||||
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
|
||||
|
||||
rails-erb-loader@^5.5.2:
|
||||
version "5.5.2"
|
||||
resolved "https://registry.yarnpkg.com/rails-erb-loader/-/rails-erb-loader-5.5.2.tgz#db3fa8ac89600f09d179a1a70a2ca18c592576ea"
|
||||
integrity sha512-cjQH9SuSvRPhnWkvjmmAW/S4AFVDfAtYnQO4XpKJ8xpRdZayT73iXoE+IPc3VzN03noZXhVmyvsCvKvHj4LY6w==
|
||||
dependencies:
|
||||
loader-utils "^1.1.0"
|
||||
lodash.defaults "^4.2.0"
|
||||
|
||||
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||
|
||||
Reference in New Issue
Block a user