Merge branch 'main' into main

This commit is contained in:
Ivo Barros 2023-06-22 04:23:35 +01:00 committed by GitHub
commit aa36fe6e5e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
71 changed files with 1174 additions and 980 deletions

View file

@ -2,7 +2,7 @@ import { initializeSite } from "@utils/app";
import { hydrate } from "inferno-hydrate";
import { Router } from "inferno-router";
import { App } from "../shared/components/app/app";
import { HistoryService } from "../shared/services/HistoryService";
import { HistoryService } from "../shared/services";
import "bootstrap/js/dist/collapse";
import "bootstrap/js/dist/dropdown";

View file

@ -1,6 +1,6 @@
import type { Request, Response } from "express";
import { LemmyHttp } from "lemmy-js-client";
import { getHttpBaseInternal } from "../../shared/env";
import { getHttpBaseExternal, getHttpBaseInternal } from "../../shared/env";
import { wrapClient } from "../../shared/services/HttpService";
import generateManifestJson from "../utils/generate-manifest-json";
import { setForwardedHeaders } from "../utils/set-forwarded-headers";
@ -9,7 +9,7 @@ let manifest: Awaited<ReturnType<typeof generateManifestJson>> | undefined =
undefined;
export default async (req: Request, res: Response) => {
if (!manifest) {
if (!manifest || manifest.start_url !== getHttpBaseExternal()) {
const headers = setForwardedHeaders(req.headers);
const client = wrapClient(
new LemmyHttp(getHttpBaseInternal(), { fetchFunction: fetch, headers })

View file

@ -2,9 +2,9 @@ import { isAuthPath, setIsoData } from "@utils/app";
import { Component, RefObject, createRef, linkEvent } from "inferno";
import { Provider } from "inferno-i18next-dess";
import { Route, Switch } from "inferno-router";
import { i18n } from "../../i18next";
import { IsoDataOptionalSite } from "../../interfaces";
import { routes } from "../../routes";
import { I18NextService } from "../../services";
import AuthGuard from "../common/auth-guard";
import ErrorGuard from "../common/error-guard";
import { ErrorPage } from "./error-page";
@ -31,13 +31,13 @@ export class App extends Component<any, any> {
return (
<>
<Provider i18next={i18n}>
<Provider i18next={I18NextService.i18n}>
<div id="app" className="lemmy-site">
<a
className="skip-link bg-light text-dark p-2 text-decoration-none position-absolute start-0 z-3"
onClick={linkEvent(this, this.handleJumpToContent)}
>
${i18n.t("jump_to_content", "Jump to content")}
${I18NextService.i18n.t("jump_to_content", "Jump to content")}
</a>
{siteView && (
<Theme defaultTheme={siteView.local_site.default_theme} />

View file

@ -2,8 +2,8 @@ import { setIsoData } from "@utils/app";
import { Component } from "inferno";
import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router";
import { i18n } from "../../i18next";
import { IsoDataOptionalSite } from "../../interfaces";
import { I18NextService } from "../../services";
export class ErrorPage extends Component<any, any> {
private isoData: IsoDataOptionalSite = setIsoData(this.context);
@ -19,8 +19,8 @@ export class ErrorPage extends Component<any, any> {
<div className="error-page container-lg text-center">
<h1>
{errorPageData
? i18n.t("error_page_title")
: i18n.t("not_found_page_title")}
? I18NextService.i18n.t("error_page_title")
: I18NextService.i18n.t("not_found_page_title")}
</h1>
{errorPageData ? (
<T i18nKey="error_page_paragraph" className="p-4" parent="p">
@ -28,18 +28,18 @@ export class ErrorPage extends Component<any, any> {
<a href="https://matrix.to/#/#lemmy-space:matrix.org">#</a>#
</T>
) : (
<p>{i18n.t("not_found_page_message")}</p>
<p>{I18NextService.i18n.t("not_found_page_message")}</p>
)}
{!errorPageData && (
<Link to="/" replace>
{i18n.t("not_found_return_home_button")}
{I18NextService.i18n.t("not_found_return_home_button")}
</Link>
)}
{errorPageData?.adminMatrixIds &&
errorPageData.adminMatrixIds.length > 0 && (
<>
<div>
{i18n.t("error_page_admin_matrix", {
{I18NextService.i18n.t("error_page_admin_matrix", {
instance:
this.isoData.site_res?.site_view.site.name ??
"this instance",

View file

@ -2,7 +2,7 @@ import { Component } from "inferno";
import { NavLink } from "inferno-router";
import { GetSiteResponse } from "lemmy-js-client";
import { docsUrl, joinLemmyUrl, repoUrl } from "../../config";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { VERSION } from "../../version";
interface FooterProps {
@ -29,36 +29,36 @@ export class Footer extends Component<FooterProps, any> {
</li>
<li className="nav-item">
<NavLink className="nav-link" to="/modlog">
{i18n.t("modlog")}
{I18NextService.i18n.t("modlog")}
</NavLink>
</li>
{this.props.site?.site_view.local_site.legal_information && (
<li className="nav-item">
<NavLink className="nav-link" to="/legal">
{i18n.t("legal_information")}
{I18NextService.i18n.t("legal_information")}
</NavLink>
</li>
)}
{this.props.site?.site_view.local_site.federation_enabled && (
<li className="nav-item">
<NavLink className="nav-link" to="/instances">
{i18n.t("instances")}
{I18NextService.i18n.t("instances")}
</NavLink>
</li>
)}
<li className="nav-item">
<a className="nav-link" href={docsUrl}>
{i18n.t("docs")}
{I18NextService.i18n.t("docs")}
</a>
</li>
<li className="nav-item">
<a className="nav-link" href={repoUrl}>
{i18n.t("code")}
{I18NextService.i18n.t("code")}
</a>
</li>
<li className="nav-item">
<a className="nav-link" href={joinLemmyUrl}>
{i18n.t("join_lemmy")}
{I18NextService.i18n.t("join_lemmy")}
</a>
</li>
</ul>

View file

@ -11,8 +11,7 @@ import {
GetUnreadRegistrationApplicationCountResponse,
} from "lemmy-js-client";
import { donateLemmyUrl, updateUnreadCountsInterval } from "../../config";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { toast } from "../../toast";
import { Icon } from "../common/icon";
@ -102,7 +101,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to="/inbox"
className="p-1 nav-link border-0 nav-messages"
title={i18n.t("unread_messages", {
title={I18NextService.i18n.t("unread_messages", {
count: Number(this.state.unreadApplicationCountRes.state),
formattedCount: numToSI(this.unreadInboxCount),
})}
@ -121,7 +120,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to="/reports"
className="p-1 nav-link border-0"
title={i18n.t("unread_reports", {
title={I18NextService.i18n.t("unread_reports", {
count: Number(this.unreadReportCount),
formattedCount: numToSI(this.unreadReportCount),
})}
@ -141,10 +140,13 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to="/registration_applications"
className="p-1 nav-link border-0"
title={i18n.t("unread_registration_applications", {
title={I18NextService.i18n.t(
"unread_registration_applications",
{
count: Number(this.unreadApplicationCount),
formattedCount: numToSI(this.unreadApplicationCount),
})}
}
)}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
<Icon icon="clipboard" />
@ -162,7 +164,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
className="navbar-toggler border-0 p-1"
type="button"
aria-label="menu"
data-tippy-content={i18n.t("expand_here")}
data-tippy-content={I18NextService.i18n.t("expand_here")}
data-bs-toggle="collapse"
data-bs-target="#navbarDropdown"
aria-controls="navbarDropdown"
@ -181,10 +183,10 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to="/communities"
className="nav-link"
title={i18n.t("communities")}
title={I18NextService.i18n.t("communities")}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
{i18n.t("communities")}
{I18NextService.i18n.t("communities")}
</NavLink>
</li>
<li className="nav-item">
@ -198,10 +200,10 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
state: { prevPath: this.currentLocation },
}}
className="nav-link"
title={i18n.t("create_post")}
title={I18NextService.i18n.t("create_post")}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
{i18n.t("create_post")}
{I18NextService.i18n.t("create_post")}
</NavLink>
</li>
{this.props.siteRes && canCreateCommunity(this.props.siteRes) && (
@ -209,22 +211,22 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to="/create_community"
className="nav-link"
title={i18n.t("create_community")}
title={I18NextService.i18n.t("create_community")}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
{i18n.t("create_community")}
{I18NextService.i18n.t("create_community")}
</NavLink>
</li>
)}
<li className="nav-item">
<a
className="nav-link d-inline-flex align-items-center d-md-inline-block"
title={i18n.t("support_lemmy")}
title={I18NextService.i18n.t("support_lemmy")}
href={donateLemmyUrl}
>
<Icon icon="heart" classes="small" />
<span className="d-inline ms-1 d-md-none ms-md-0">
{i18n.t("support_lemmy")}
{I18NextService.i18n.t("support_lemmy")}
</span>
</a>
</li>
@ -234,12 +236,12 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to="/search"
className="nav-link d-inline-flex align-items-center d-md-inline-block"
title={i18n.t("search")}
title={I18NextService.i18n.t("search")}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
<Icon icon="search" />
<span className="d-inline ms-1 d-md-none ms-md-0">
{i18n.t("search")}
{I18NextService.i18n.t("search")}
</span>
</NavLink>
</li>
@ -248,12 +250,12 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to="/admin"
className="nav-link d-inline-flex align-items-center d-md-inline-block"
title={i18n.t("admin_settings")}
title={I18NextService.i18n.t("admin_settings")}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
<Icon icon="settings" />
<span className="d-inline ms-1 d-md-none ms-md-0">
{i18n.t("admin_settings")}
{I18NextService.i18n.t("admin_settings")}
</span>
</NavLink>
</li>
@ -264,7 +266,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
className="nav-link d-inline-flex align-items-center d-md-inline-block"
to="/inbox"
title={i18n.t("unread_messages", {
title={I18NextService.i18n.t("unread_messages", {
count: Number(this.unreadInboxCount),
formattedCount: numToSI(this.unreadInboxCount),
})}
@ -272,7 +274,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
>
<Icon icon="bell" />
<span className="badge text-bg-light d-inline ms-1 d-md-none ms-md-0">
{i18n.t("unread_messages", {
{I18NextService.i18n.t("unread_messages", {
count: Number(this.unreadInboxCount),
formattedCount: numToSI(this.unreadInboxCount),
})}
@ -289,7 +291,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
className="nav-link d-inline-flex align-items-center d-md-inline-block"
to="/reports"
title={i18n.t("unread_reports", {
title={I18NextService.i18n.t("unread_reports", {
count: Number(this.unreadReportCount),
formattedCount: numToSI(this.unreadReportCount),
})}
@ -297,7 +299,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
>
<Icon icon="shield" />
<span className="badge text-bg-light d-inline ms-1 d-md-none ms-md-0">
{i18n.t("unread_reports", {
{I18NextService.i18n.t("unread_reports", {
count: Number(this.unreadReportCount),
formattedCount: numToSI(this.unreadReportCount),
})}
@ -315,18 +317,26 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to="/registration_applications"
className="nav-link d-inline-flex align-items-center d-md-inline-block"
title={i18n.t("unread_registration_applications", {
title={I18NextService.i18n.t(
"unread_registration_applications",
{
count: Number(this.unreadApplicationCount),
formattedCount: numToSI(this.unreadApplicationCount),
})}
}
)}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
<Icon icon="clipboard" />
<span className="badge text-bg-light d-inline ms-1 d-md-none ms-md-0">
{i18n.t("unread_registration_applications", {
{I18NextService.i18n.t(
"unread_registration_applications",
{
count: Number(this.unreadApplicationCount),
formattedCount: numToSI(this.unreadApplicationCount),
})}
formattedCount: numToSI(
this.unreadApplicationCount
),
}
)}
</span>
{this.unreadApplicationCount > 0 && (
<span className="mx-1 badge text-bg-light">
@ -357,22 +367,22 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to={`/u/${person.name}`}
className="dropdown-item px-2"
title={i18n.t("profile")}
title={I18NextService.i18n.t("profile")}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
<Icon icon="user" classes="me-1" />
{i18n.t("profile")}
{I18NextService.i18n.t("profile")}
</NavLink>
</li>
<li>
<NavLink
to="/settings"
className="dropdown-item px-2"
title={i18n.t("settings")}
title={I18NextService.i18n.t("settings")}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
<Icon icon="settings" classes="me-1" />
{i18n.t("settings")}
{I18NextService.i18n.t("settings")}
</NavLink>
</li>
<li>
@ -384,7 +394,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
onClick={linkEvent(this, handleLogOut)}
>
<Icon icon="log-out" classes="me-1" />
{i18n.t("logout")}
{I18NextService.i18n.t("logout")}
</button>
</li>
</ul>
@ -397,20 +407,20 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<NavLink
to="/login"
className="nav-link"
title={i18n.t("login")}
title={I18NextService.i18n.t("login")}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
{i18n.t("login")}
{I18NextService.i18n.t("login")}
</NavLink>
</li>
<li className="nav-item">
<NavLink
to="/signup"
className="nav-link"
title={i18n.t("sign_up")}
title={I18NextService.i18n.t("sign_up")}
onMouseUp={linkEvent(this, handleCollapseClick)}
>
{i18n.t("sign_up")}
{I18NextService.i18n.t("sign_up")}
</NavLink>
</li>
</>
@ -504,7 +514,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
if (UserService.Instance.myUserInfo) {
document.addEventListener("DOMContentLoaded", function () {
if (!Notification) {
toast(i18n.t("notifications_error"), "danger");
toast(I18NextService.i18n.t("notifications_error"), "danger");
return;
}

View file

@ -4,9 +4,8 @@ import { Component } from "inferno";
import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router";
import { CreateComment, EditComment, Language } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { CommentNodeI } from "../../interfaces";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { Icon } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea";
@ -58,7 +57,7 @@ export class CommentForm extends Component<CommentFormProps, any> {
disabled={this.props.disabled}
onSubmit={this.handleCommentSubmit}
onReplyCancel={this.props.onReplyCancel}
placeholder={i18n.t("comment_here")}
placeholder={I18NextService.i18n.t("comment_here") ?? undefined}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
/>
@ -79,10 +78,10 @@ export class CommentForm extends Component<CommentFormProps, any> {
get buttonTitle(): string {
return typeof this.props.node === "number"
? capitalizeFirstLetter(i18n.t("post"))
? capitalizeFirstLetter(I18NextService.i18n.t("post"))
: this.props.edit
? capitalizeFirstLetter(i18n.t("save"))
: capitalizeFirstLetter(i18n.t("reply"));
? capitalizeFirstLetter(I18NextService.i18n.t("save"))
: capitalizeFirstLetter(I18NextService.i18n.t("reply"));
}
handleCommentSubmit(content: string, form_id: string, language_id?: number) {

View file

@ -48,7 +48,6 @@ import {
} from "lemmy-js-client";
import moment from "moment";
import { commentTreeMaxDepth } from "../../config";
import { i18n } from "../../i18next";
import {
BanType,
CommentNodeI,
@ -57,7 +56,7 @@ import {
VoteType,
} from "../../interfaces";
import { mdToHtml, mdToHtmlNoImages } from "../../markdown";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { setupTippy } from "../../tippy";
import { Icon, PurgeWarning, Spinner } from "../common/icon";
import { MomentTime } from "../common/moment-time";
@ -241,8 +240,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
const purgeTypeText =
this.state.purgeType == PurgeType.Comment
? i18n.t("purge_comment")
: `${i18n.t("purge")} ${cv.creator.name}`;
? I18NextService.i18n.t("purge_comment")
: `${I18NextService.i18n.t("purge")} ${cv.creator.name}`;
const canMod_ = canMod(
cv.creator.id,
@ -314,27 +313,27 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)}
{this.isPostCreator && (
<div className="badge text-bg-light d-none d-sm-inline me-2">
{i18n.t("creator")}
{I18NextService.i18n.t("creator")}
</div>
)}
{isMod_ && (
<div className="badge text-bg-light d-none d-sm-inline me-2">
{i18n.t("mod")}
{I18NextService.i18n.t("mod")}
</div>
)}
{isAdmin_ && (
<div className="badge text-bg-light d-none d-sm-inline me-2">
{i18n.t("admin")}
{I18NextService.i18n.t("admin")}
</div>
)}
{cv.creator.bot_account && (
<div className="badge text-bg-light d-none d-sm-inline me-2">
{i18n.t("bot_account").toLowerCase()}
{I18NextService.i18n.t("bot_account").toLowerCase()}
</div>
)}
{this.props.showCommunity && (
<>
<span className="mx-1">{i18n.t("to")}</span>
<span className="mx-1">{I18NextService.i18n.t("to")}</span>
<CommunityLink community={cv.community} />
<span className="mx-2"></span>
<Link className="me-2" to={`/post/${cv.post.id}`}>
@ -366,7 +365,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
) : (
<span
className="me-1 font-weight-bold"
aria-label={i18n.t("number_of_points", {
aria-label={I18NextService.i18n.t("number_of_points", {
count: Number(this.commentView.counts.score),
formattedCount: numToSI(
this.commentView.counts.score
@ -426,13 +425,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
onClick={linkEvent(this, this.handleMarkAsRead)}
data-tippy-content={
this.commentReplyOrMentionRead
? i18n.t("mark_as_unread")
: i18n.t("mark_as_read")
? I18NextService.i18n.t("mark_as_unread")
: I18NextService.i18n.t("mark_as_read")
}
aria-label={
this.commentReplyOrMentionRead
? i18n.t("mark_as_unread")
: i18n.t("mark_as_read")
? I18NextService.i18n.t("mark_as_unread")
: I18NextService.i18n.t("mark_as_read")
}
>
{this.state.readLoading ? (
@ -456,8 +455,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
: "text-muted"
}`}
onClick={linkEvent(this, this.handleUpvote)}
data-tippy-content={i18n.t("upvote")}
aria-label={i18n.t("upvote")}
data-tippy-content={I18NextService.i18n.t("upvote")}
aria-label={I18NextService.i18n.t("upvote")}
aria-pressed={this.commentView.my_vote === 1}
>
{this.state.upvoteLoading ? (
@ -483,8 +482,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
: "text-muted"
}`}
onClick={linkEvent(this, this.handleDownvote)}
data-tippy-content={i18n.t("downvote")}
aria-label={i18n.t("downvote")}
data-tippy-content={I18NextService.i18n.t("downvote")}
aria-label={I18NextService.i18n.t("downvote")}
aria-pressed={this.commentView.my_vote === -1}
>
{this.state.downvoteLoading ? (
@ -506,8 +505,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleReplyClick)}
data-tippy-content={i18n.t("reply")}
aria-label={i18n.t("reply")}
data-tippy-content={I18NextService.i18n.t("reply")}
aria-label={I18NextService.i18n.t("reply")}
>
<Icon icon="reply1" classes="icon-inline" />
</button>
@ -515,8 +514,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button
className="btn btn-link btn-animate text-muted btn-more"
onClick={linkEvent(this, this.handleShowAdvanced)}
data-tippy-content={i18n.t("more")}
aria-label={i18n.t("more")}
data-tippy-content={I18NextService.i18n.t("more")}
aria-label={I18NextService.i18n.t("more")}
>
<Icon icon="more-vertical" classes="icon-inline" />
</button>
@ -527,7 +526,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<Link
className="btn btn-link btn-animate text-muted"
to={`/create_private_message/${cv.creator.id}`}
title={i18n.t("message").toLowerCase()}
title={I18NextService.i18n
.t("message")
.toLowerCase()}
>
<Icon icon="mail" />
</Link>
@ -537,10 +538,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleShowReportDialog
)}
data-tippy-content={i18n.t(
data-tippy-content={I18NextService.i18n.t(
"show_report_dialog"
)}
aria-label={I18NextService.i18n.t(
"show_report_dialog"
)}
aria-label={i18n.t("show_report_dialog")}
>
<Icon icon="flag" />
</button>
@ -550,8 +553,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleBlockPerson
)}
data-tippy-content={i18n.t("block_user")}
aria-label={i18n.t("block_user")}
data-tippy-content={I18NextService.i18n.t(
"block_user"
)}
aria-label={I18NextService.i18n.t("block_user")}
>
{this.state.blockPersonLoading ? (
<Spinner />
@ -565,10 +570,14 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleSaveComment)}
data-tippy-content={
cv.saved ? i18n.t("unsave") : i18n.t("save")
cv.saved
? I18NextService.i18n.t("unsave")
: I18NextService.i18n.t("save")
}
aria-label={
cv.saved ? i18n.t("unsave") : i18n.t("save")
cv.saved
? I18NextService.i18n.t("unsave")
: I18NextService.i18n.t("save")
}
>
{this.state.saveLoading ? (
@ -585,8 +594,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t("view_source")}
aria-label={i18n.t("view_source")}
data-tippy-content={I18NextService.i18n.t(
"view_source"
)}
aria-label={I18NextService.i18n.t("view_source")}
>
<Icon
icon="file-text"
@ -600,8 +611,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t("edit")}
aria-label={i18n.t("edit")}
data-tippy-content={I18NextService.i18n.t(
"edit"
)}
aria-label={I18NextService.i18n.t("edit")}
>
<Icon icon="edit" classes="icon-inline" />
</button>
@ -613,13 +626,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)}
data-tippy-content={
!cv.comment.deleted
? i18n.t("delete")
: i18n.t("restore")
? I18NextService.i18n.t("delete")
: I18NextService.i18n.t("restore")
}
aria-label={
!cv.comment.deleted
? i18n.t("delete")
: i18n.t("restore")
? I18NextService.i18n.t("delete")
: I18NextService.i18n.t("restore")
}
>
{this.state.deleteLoading ? (
@ -643,13 +656,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)}
data-tippy-content={
!cv.comment.distinguished
? i18n.t("distinguish")
: i18n.t("undistinguish")
? I18NextService.i18n.t("distinguish")
: I18NextService.i18n.t("undistinguish")
}
aria-label={
!cv.comment.distinguished
? i18n.t("distinguish")
: i18n.t("undistinguish")
? I18NextService.i18n.t("distinguish")
: I18NextService.i18n.t("undistinguish")
}
>
<Icon
@ -672,9 +685,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleModRemoveShow
)}
aria-label={i18n.t("remove")}
aria-label={I18NextService.i18n.t("remove")}
>
{i18n.t("remove")}
{I18NextService.i18n.t("remove")}
</button>
) : (
<button
@ -683,12 +696,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleRemoveComment
)}
aria-label={i18n.t("restore")}
aria-label={I18NextService.i18n.t("restore")}
>
{this.state.removeLoading ? (
<Spinner />
) : (
i18n.t("restore")
I18NextService.i18n.t("restore")
)}
</button>
)}
@ -705,9 +718,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleModBanFromCommunityShow
)}
aria-label={i18n.t("ban_from_community")}
aria-label={I18NextService.i18n.t(
"ban_from_community"
)}
>
{i18n.t("ban_from_community")}
{I18NextService.i18n.t(
"ban_from_community"
)}
</button>
) : (
<button
@ -716,12 +733,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleBanPersonFromCommunity
)}
aria-label={i18n.t("unban")}
aria-label={I18NextService.i18n.t("unban")}
>
{this.state.banLoading ? (
<Spinner />
) : (
i18n.t("unban")
I18NextService.i18n.t("unban")
)}
</button>
))}
@ -735,21 +752,25 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)}
aria-label={
isMod_
? i18n.t("remove_as_mod")
: i18n.t("appoint_as_mod")
? I18NextService.i18n.t("remove_as_mod")
: I18NextService.i18n.t(
"appoint_as_mod"
)
}
>
{isMod_
? i18n.t("remove_as_mod")
: i18n.t("appoint_as_mod")}
? I18NextService.i18n.t("remove_as_mod")
: I18NextService.i18n.t("appoint_as_mod")}
</button>
) : (
<>
<button
className="btn btn-link btn-animate text-muted"
aria-label={i18n.t("are_you_sure")}
aria-label={I18NextService.i18n.t(
"are_you_sure"
)}
>
{i18n.t("are_you_sure")}
{I18NextService.i18n.t("are_you_sure")}
</button>
<button
className="btn btn-link btn-animate text-muted"
@ -757,12 +778,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleAddModToCommunity
)}
aria-label={i18n.t("yes")}
aria-label={I18NextService.i18n.t("yes")}
>
{this.state.addModLoading ? (
<Spinner />
) : (
i18n.t("yes")
I18NextService.i18n.t("yes")
)}
</button>
<button
@ -771,9 +792,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleCancelConfirmAppointAsMod
)}
aria-label={i18n.t("no")}
aria-label={I18NextService.i18n.t("no")}
>
{i18n.t("no")}
{I18NextService.i18n.t("no")}
</button>
</>
))}
@ -790,17 +811,21 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleShowConfirmTransferCommunity
)}
aria-label={i18n.t("transfer_community")}
aria-label={I18NextService.i18n.t(
"transfer_community"
)}
>
{i18n.t("transfer_community")}
{I18NextService.i18n.t("transfer_community")}
</button>
) : (
<>
<button
className="btn btn-link btn-animate text-muted"
aria-label={i18n.t("are_you_sure")}
aria-label={I18NextService.i18n.t(
"are_you_sure"
)}
>
{i18n.t("are_you_sure")}
{I18NextService.i18n.t("are_you_sure")}
</button>
<button
className="btn btn-link btn-animate text-muted"
@ -808,12 +833,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleTransferCommunity
)}
aria-label={i18n.t("yes")}
aria-label={I18NextService.i18n.t("yes")}
>
{this.state.transferCommunityLoading ? (
<Spinner />
) : (
i18n.t("yes")
I18NextService.i18n.t("yes")
)}
</button>
<button
@ -823,9 +848,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this
.handleCancelShowConfirmTransferCommunity
)}
aria-label={i18n.t("no")}
aria-label={I18NextService.i18n.t("no")}
>
{i18n.t("no")}
{I18NextService.i18n.t("no")}
</button>
</>
))}
@ -840,9 +865,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handlePurgePersonShow
)}
aria-label={i18n.t("purge_user")}
aria-label={I18NextService.i18n.t(
"purge_user"
)}
>
{i18n.t("purge_user")}
{I18NextService.i18n.t("purge_user")}
</button>
<button
className="btn btn-link btn-animate text-muted"
@ -850,9 +877,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handlePurgeCommentShow
)}
aria-label={i18n.t("purge_comment")}
aria-label={I18NextService.i18n.t(
"purge_comment"
)}
>
{i18n.t("purge_comment")}
{I18NextService.i18n.t("purge_comment")}
</button>
{!isBanned(cv.creator) ? (
@ -862,9 +891,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleModBanShow
)}
aria-label={i18n.t("ban_from_site")}
aria-label={I18NextService.i18n.t(
"ban_from_site"
)}
>
{i18n.t("ban_from_site")}
{I18NextService.i18n.t("ban_from_site")}
</button>
) : (
<button
@ -873,12 +904,14 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleBanPerson
)}
aria-label={i18n.t("unban_from_site")}
aria-label={I18NextService.i18n.t(
"unban_from_site"
)}
>
{this.state.banLoading ? (
<Spinner />
) : (
i18n.t("unban_from_site")
I18NextService.i18n.t("unban_from_site")
)}
</button>
)}
@ -895,18 +928,24 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)}
aria-label={
isAdmin_
? i18n.t("remove_as_admin")
: i18n.t("appoint_as_admin")
? I18NextService.i18n.t(
"remove_as_admin"
)
: I18NextService.i18n.t(
"appoint_as_admin"
)
}
>
{isAdmin_
? i18n.t("remove_as_admin")
: i18n.t("appoint_as_admin")}
? I18NextService.i18n.t("remove_as_admin")
: I18NextService.i18n.t(
"appoint_as_admin"
)}
</button>
) : (
<>
<button className="btn btn-link btn-animate text-muted">
{i18n.t("are_you_sure")}
{I18NextService.i18n.t("are_you_sure")}
</button>
<button
className="btn btn-link btn-animate text-muted"
@ -914,12 +953,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleAddAdmin
)}
aria-label={i18n.t("yes")}
aria-label={I18NextService.i18n.t("yes")}
>
{this.state.addAdminLoading ? (
<Spinner />
) : (
i18n.t("yes")
I18NextService.i18n.t("yes")
)}
</button>
<button
@ -928,9 +967,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this,
this.handleCancelConfirmAppointAsAdmin
)}
aria-label={i18n.t("no")}
aria-label={I18NextService.i18n.t("no")}
>
{i18n.t("no")}
{I18NextService.i18n.t("no")}
</button>
</>
))}
@ -961,7 +1000,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<Spinner />
) : (
<>
{i18n.t("x_more_replies", {
{I18NextService.i18n.t("x_more_replies", {
count: node.comment_view.counts.child_count,
formattedCount: numToSI(
node.comment_view.counts.child_count
@ -983,22 +1022,22 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
className="visually-hidden"
htmlFor={`mod-remove-reason-${cv.comment.id}`}
>
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id={`mod-remove-reason-${cv.comment.id}`}
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
value={this.state.removeReason}
onInput={linkEvent(this, this.handleModRemoveReasonChange)}
/>
<button
type="submit"
className="btn btn-secondary"
aria-label={i18n.t("remove_comment")}
aria-label={I18NextService.i18n.t("remove_comment")}
>
{i18n.t("remove_comment")}
{I18NextService.i18n.t("remove_comment")}
</button>
</form>
)}
@ -1011,23 +1050,23 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
className="visually-hidden"
htmlFor={`report-reason-${cv.comment.id}`}
>
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
required
id={`report-reason-${cv.comment.id}`}
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
value={this.state.reportReason}
onInput={linkEvent(this, this.handleReportReasonChange)}
/>
<button
type="submit"
className="btn btn-secondary"
aria-label={i18n.t("create_report")}
aria-label={I18NextService.i18n.t("create_report")}
>
{i18n.t("create_report")}
{I18NextService.i18n.t("create_report")}
</button>
</form>
)}
@ -1038,13 +1077,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
className="col-form-label"
htmlFor={`mod-ban-reason-${cv.comment.id}`}
>
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id={`mod-ban-reason-${cv.comment.id}`}
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)}
/>
@ -1052,13 +1091,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
className="col-form-label"
htmlFor={`mod-ban-expires-${cv.comment.id}`}
>
{i18n.t("expires")}
{I18NextService.i18n.t("expires")}
</label>
<input
type="number"
id={`mod-ban-expires-${cv.comment.id}`}
className="form-control me-2"
placeholder={i18n.t("number_of_days")}
placeholder={I18NextService.i18n.t("number_of_days")}
value={this.state.banExpireDays}
onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
/>
@ -1074,9 +1113,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<label
className="form-check-label"
htmlFor="mod-ban-remove-data"
title={i18n.t("remove_content_more")}
title={I18NextService.i18n.t("remove_content_more")}
>
{i18n.t("remove_content")}
{I18NextService.i18n.t("remove_content")}
</label>
</div>
</div>
@ -1084,19 +1123,19 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{/* TODO hold off on expires until later */}
{/* <div class="mb-3 row"> */}
{/* <label class="col-form-label">Expires</label> */}
{/* <input type="date" class="form-control me-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
{/* <input type="date" class="form-control me-2" placeholder={I18NextService.i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
{/* </div> */}
<div className="mb-3 row">
<button
type="submit"
className="btn btn-secondary"
aria-label={i18n.t("ban")}
aria-label={I18NextService.i18n.t("ban")}
>
{this.state.banLoading ? (
<Spinner />
) : (
<span>
{i18n.t("ban")} {cv.creator.name}
{I18NextService.i18n.t("ban")} {cv.creator.name}
</span>
)}
</button>
@ -1108,13 +1147,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<form onSubmit={linkEvent(this, this.handlePurgeBothSubmit)}>
<PurgeWarning />
<label className="visually-hidden" htmlFor="purge-reason">
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id="purge-reason"
className="form-control my-3"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
value={this.state.purgeReason}
onInput={linkEvent(this, this.handlePurgeReasonChange)}
/>
@ -1209,8 +1248,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
});
const title = this.props.showContext
? i18n.t("show_context")
: i18n.t("link");
? I18NextService.i18n.t("show_context")
: I18NextService.i18n.t("link");
// The context button should show the parent comment by default
const parentCommentId = getCommentParentId(cv.comment) ?? cv.comment.id;
@ -1255,17 +1294,17 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
}
get pointsTippy(): string {
const points = i18n.t("number_of_points", {
const points = I18NextService.i18n.t("number_of_points", {
count: Number(this.commentView.counts.score),
formattedCount: numToSI(this.commentView.counts.score),
});
const upvotes = i18n.t("number_of_upvotes", {
const upvotes = I18NextService.i18n.t("number_of_upvotes", {
count: Number(this.commentView.counts.upvotes),
formattedCount: numToSI(this.commentView.counts.upvotes),
});
const downvotes = i18n.t("number_of_downvotes", {
const downvotes = I18NextService.i18n.t("number_of_downvotes", {
count: Number(this.commentView.counts.downvotes),
formattedCount: numToSI(this.commentView.counts.downvotes),
});
@ -1274,15 +1313,17 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
}
get expandText(): string {
return this.state.collapsed ? i18n.t("expand") : i18n.t("collapse");
return this.state.collapsed
? I18NextService.i18n.t("expand")
: I18NextService.i18n.t("collapse");
}
get commentUnlessRemoved(): string {
const comment = this.commentView.comment;
return comment.removed
? `*${i18n.t("removed")}*`
? `*${I18NextService.i18n.t("removed")}*`
: comment.deleted
? `*${i18n.t("deleted")}*`
? `*${I18NextService.i18n.t("deleted")}*`
: comment.content;
}

View file

@ -6,8 +6,8 @@ import {
CommentView,
ResolveCommentReport,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { CommentNodeI, CommentViewType } from "../../interfaces";
import { I18NextService } from "../../services";
import { Icon, Spinner } from "../common/icon";
import { PersonListing } from "../person/person-listing";
import { CommentNode } from "./comment-node";
@ -43,7 +43,7 @@ export class CommentReport extends Component<
render() {
const r = this.props.report;
const comment = r.comment;
const tippyContent = i18n.t(
const tippyContent = I18NextService.i18n.t(
r.comment_report.resolved ? "unresolve_report" : "resolve_report"
);
@ -102,10 +102,11 @@ export class CommentReport extends Component<
onEditComment={() => Promise.resolve({ state: "empty" })}
/>
<div>
{i18n.t("reporter")}: <PersonListing person={r.creator} />
{I18NextService.i18n.t("reporter")}:{" "}
<PersonListing person={r.creator} />
</div>
<div>
{i18n.t("reason")}: {r.comment_report.reason}
{I18NextService.i18n.t("reason")}: {r.comment_report.reason}
</div>
{r.resolver && (
<div>

View file

@ -5,7 +5,7 @@ import {
CommunityId,
SiteAggregates,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
interface BadgesProps {
counts: CommunityAggregates | SiteAggregates;
@ -29,66 +29,82 @@ export const Badges = ({ counts, communityId }: BadgesProps) => {
<ul className="badges my-1 list-inline">
<li
className="list-inline-item badge text-bg-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_day", {
data-tippy-content={I18NextService.i18n.t(
"active_users_in_the_last_day",
{
count: Number(counts.users_active_day),
formattedCount: numToSI(counts.users_active_day),
})}
}
)}
>
{i18n.t("number_of_users", {
{I18NextService.i18n.t("number_of_users", {
count: Number(counts.users_active_day),
formattedCount: numToSI(counts.users_active_day),
})}{" "}
/ {i18n.t("day")}
/ {I18NextService.i18n.t("day")}
</li>
<li
className="list-inline-item badge text-bg-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_week", {
data-tippy-content={I18NextService.i18n.t(
"active_users_in_the_last_week",
{
count: Number(counts.users_active_week),
formattedCount: numToSI(counts.users_active_week),
})}
}
)}
>
{i18n.t("number_of_users", {
{I18NextService.i18n.t("number_of_users", {
count: Number(counts.users_active_week),
formattedCount: numToSI(counts.users_active_week),
})}{" "}
/ {i18n.t("week")}
/ {I18NextService.i18n.t("week")}
</li>
<li
className="list-inline-item badge text-bg-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_month", {
data-tippy-content={I18NextService.i18n.t(
"active_users_in_the_last_month",
{
count: Number(counts.users_active_month),
formattedCount: numToSI(counts.users_active_month),
})}
}
)}
>
{i18n.t("number_of_users", {
{I18NextService.i18n.t("number_of_users", {
count: Number(counts.users_active_month),
formattedCount: numToSI(counts.users_active_month),
})}{" "}
/ {i18n.t("month")}
/ {I18NextService.i18n.t("month")}
</li>
<li
className="list-inline-item badge text-bg-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_six_months", {
data-tippy-content={I18NextService.i18n.t(
"active_users_in_the_last_six_months",
{
count: Number(counts.users_active_half_year),
formattedCount: numToSI(counts.users_active_half_year),
})}
}
)}
>
{i18n.t("number_of_users", {
{I18NextService.i18n.t("number_of_users", {
count: Number(counts.users_active_half_year),
formattedCount: numToSI(counts.users_active_half_year),
})}{" "}
/ {i18n.t("number_of_months", { count: 6, formattedCount: 6 })}
/{" "}
{I18NextService.i18n.t("number_of_months", {
count: 6,
formattedCount: 6,
})}
</li>
{isSiteAggregates(counts) && (
<>
<li className="list-inline-item badge text-bg-secondary">
{i18n.t("number_of_users", {
{I18NextService.i18n.t("number_of_users", {
count: Number(counts.users),
formattedCount: numToSI(counts.users),
})}
</li>
<li className="list-inline-item badge text-bg-secondary">
{i18n.t("number_of_communities", {
{I18NextService.i18n.t("number_of_communities", {
count: Number(counts.communities),
formattedCount: numToSI(counts.communities),
})}
@ -97,20 +113,20 @@ export const Badges = ({ counts, communityId }: BadgesProps) => {
)}
{isCommunityAggregates(counts) && (
<li className="list-inline-item badge text-bg-secondary">
{i18n.t("number_of_subscribers", {
{I18NextService.i18n.t("number_of_subscribers", {
count: Number(counts.subscribers),
formattedCount: numToSI(counts.subscribers),
})}
</li>
)}
<li className="list-inline-item badge text-bg-secondary">
{i18n.t("number_of_posts", {
{I18NextService.i18n.t("number_of_posts", {
count: Number(counts.posts),
formattedCount: numToSI(counts.posts),
})}
</li>
<li className="list-inline-item badge text-bg-secondary">
{i18n.t("number_of_comments", {
{I18NextService.i18n.t("number_of_comments", {
count: Number(counts.comments),
formattedCount: numToSI(counts.comments),
})}
@ -120,7 +136,7 @@ export const Badges = ({ counts, communityId }: BadgesProps) => {
className="badge text-bg-primary"
to={`/modlog${communityId ? `/${communityId}` : ""}`}
>
{i18n.t("modlog")}
{I18NextService.i18n.t("modlog")}
</Link>
</li>
</ul>

View file

@ -2,7 +2,7 @@ import { randomStr } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { CommentSortType } from "lemmy-js-client";
import { relTags, sortingHelpUrl } from "../../config";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Icon } from "./icon";
interface CommentSortSelectProps {
@ -42,21 +42,21 @@ export class CommentSortSelect extends Component<
value={this.state.sort}
onChange={linkEvent(this, this.handleSortChange)}
className="sort-select form-select d-inline-block w-auto me-2 mb-2"
aria-label={i18n.t("sort_type")}
aria-label={I18NextService.i18n.t("sort_type")}
>
<option disabled aria-hidden="true">
{i18n.t("sort_type")}
{I18NextService.i18n.t("sort_type")}
</option>
<option value={"Hot"}>{i18n.t("hot")}</option>,
<option value={"Top"}>{i18n.t("top")}</option>,
<option value={"New"}>{i18n.t("new")}</option>
<option value={"Old"}>{i18n.t("old")}</option>
<option value={"Hot"}>{I18NextService.i18n.t("hot")}</option>,
<option value={"Top"}>{I18NextService.i18n.t("top")}</option>,
<option value={"New"}>{I18NextService.i18n.t("new")}</option>
<option value={"Old"}>{I18NextService.i18n.t("old")}</option>
</select>
<a
className="sort-select-help text-muted"
href={sortingHelpUrl}
rel={relTags}
title={i18n.t("sorting_help")}
title={I18NextService.i18n.t("sorting_help")}
>
<Icon icon="help-circle" classes="icon-inline" />
</a>

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from "inferno";
import { i18n } from "../../i18next";
import { DataType } from "../../interfaces";
import { I18NextService } from "../../services";
interface DataTypeSelectProps {
type_: DataType;
@ -44,7 +44,7 @@ export class DataTypeSelect extends Component<
checked={this.state.type_ == DataType.Post}
onChange={linkEvent(this, this.handleTypeChange)}
/>
{i18n.t("posts")}
{I18NextService.i18n.t("posts")}
</label>
<label
className={`pointer btn btn-outline-secondary ${
@ -58,7 +58,7 @@ export class DataTypeSelect extends Component<
checked={this.state.type_ == DataType.Comment}
onChange={linkEvent(this, this.handleTypeChange)}
/>
{i18n.t("comments")}
{I18NextService.i18n.t("comments")}
</label>
</div>
);

View file

@ -1,5 +1,5 @@
import { Component, linkEvent } from "inferno";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { EmojiMart } from "./emoji-mart";
import { Icon } from "./icon";
@ -28,8 +28,8 @@ export class EmojiPicker extends Component<EmojiPickerProps, EmojiPickerState> {
<span className="emoji-picker">
<button
className="btn btn-sm text-muted"
data-tippy-content={i18n.t("emoji")}
aria-label={i18n.t("emoji")}
data-tippy-content={I18NextService.i18n.t("emoji")}
aria-label={I18NextService.i18n.t("emoji")}
disabled={this.props.disabled}
onClick={linkEvent(this, this.togglePicker)}
>

View file

@ -2,8 +2,8 @@ import { htmlToText } from "html-to-text";
import { Component } from "inferno";
import { Helmet } from "inferno-helmet";
import { httpExternalPath } from "../../env";
import { i18n } from "../../i18next";
import { md } from "../../markdown";
import { I18NextService } from "../../services";
interface HtmlTagsProps {
title: string;
@ -21,7 +21,7 @@ export class HtmlTags extends Component<HtmlTagsProps, any> {
return (
<Helmet title={this.props.title}>
<html lang={i18n.resolvedLanguage} />
<html lang={I18NextService.i18n.resolvedLanguage} />
{["title", "og:title", "twitter:title"].map(t => (
<meta key={t} property={t} content={this.props.title} />

View file

@ -1,6 +1,6 @@
import classNames from "classnames";
import { Component } from "inferno";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
interface IconProps {
icon: string;
@ -61,7 +61,7 @@ export class PurgeWarning extends Component<any, any> {
return (
<div className="purge-warning mt-2 alert alert-danger" role="alert">
<Icon icon="alert-triangle" classes="icon-inline me-2" />
{i18n.t("purge_warning")}
{I18NextService.i18n.t("purge_warning")}
</div>
);
}

View file

@ -1,7 +1,6 @@
import { randomStr } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { i18n } from "../../i18next";
import { HttpService, UserService } from "../../services";
import { HttpService, I18NextService, UserService } from "../../services";
import { toast } from "../../toast";
import { Icon } from "./icon";
@ -50,7 +49,7 @@ export class ImageUploadForm extends Component<
/>
<a
onClick={linkEvent(this, this.handleRemoveImage)}
aria-label={i18n.t("remove")}
aria-label={I18NextService.i18n.t("remove")}
>
<Icon icon="x" classes="mini-overlay" />
</a>

View file

@ -3,8 +3,7 @@ import { randomStr } from "@utils/helpers";
import classNames from "classnames";
import { Component, linkEvent } from "inferno";
import { Language } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService } from "../../services/UserService";
import { I18NextService, UserService } from "../../services";
import { Icon } from "./icon";
interface LanguageSelectProps {
@ -53,7 +52,7 @@ export class LanguageSelect extends Component<LanguageSelectProps, any> {
<div className="language-select">
{this.props.multiple && this.props.showLanguageWarning && (
<div className="alert alert-warning" role="alert">
{i18n.t("undetermined_language_warning")}
{I18NextService.i18n.t("undetermined_language_warning")}
</div>
)}
<div className="mb-3 row">
@ -64,7 +63,9 @@ export class LanguageSelect extends Component<LanguageSelectProps, any> {
)}
htmlFor={this.id}
>
{i18n.t(this.props.multiple ? "language_plural" : "language")}
{I18NextService.i18n.t(
this.props.multiple ? "language_plural" : "language"
)}
</label>
<div
className={classNames(`col-sm-${this.props.multiple ? 9 : 10}`, {
@ -103,13 +104,13 @@ export class LanguageSelect extends Component<LanguageSelectProps, any> {
})}
id={this.id}
onChange={linkEvent(this, this.handleLanguageChange)}
aria-label={i18n.t("language_select_placeholder")}
aria-label={I18NextService.i18n.t("language_select_placeholder")}
multiple={this.props.multiple}
disabled={this.props.disabled}
>
{!this.props.multiple && (
<option selected disabled hidden>
{i18n.t("language_select_placeholder")}
{I18NextService.i18n.t("language_select_placeholder")}
</option>
)}
{filteredLangs.map(l => (

View file

@ -1,8 +1,7 @@
import { randomStr } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { ListingType } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
interface ListingTypeSelectProps {
type_: ListingType;
@ -42,7 +41,7 @@ export class ListingTypeSelect extends Component<
<div className="listing-type-select btn-group btn-group-toggle flex-wrap">
{this.props.showSubscribed && (
<label
title={i18n.t("subscribed_description")}
title={I18NextService.i18n.t("subscribed_description")}
className={`btn btn-outline-secondary
${this.state.type_ == "Subscribed" && "active"}
${!UserService.Instance.myUserInfo ? "disabled" : "pointer"}
@ -57,12 +56,12 @@ export class ListingTypeSelect extends Component<
onChange={linkEvent(this, this.handleTypeChange)}
disabled={!UserService.Instance.myUserInfo}
/>
{i18n.t("subscribed")}
{I18NextService.i18n.t("subscribed")}
</label>
)}
{this.props.showLocal && (
<label
title={i18n.t("local_description")}
title={I18NextService.i18n.t("local_description")}
className={`pointer btn btn-outline-secondary ${
this.state.type_ == "Local" && "active"
}`}
@ -75,11 +74,11 @@ export class ListingTypeSelect extends Component<
checked={this.state.type_ == "Local"}
onChange={linkEvent(this, this.handleTypeChange)}
/>
{i18n.t("local")}
{I18NextService.i18n.t("local")}
</label>
)}
<label
title={i18n.t("all_description")}
title={I18NextService.i18n.t("all_description")}
className={`pointer btn btn-outline-secondary ${
(this.state.type_ == "All" && "active") ||
(!this.props.showLocal && this.state.type_ == "Local" && "active")
@ -93,7 +92,7 @@ export class ListingTypeSelect extends Component<
checked={this.state.type_ == "All"}
onChange={linkEvent(this, this.handleTypeChange)}
/>
{i18n.t("all")}
{I18NextService.i18n.t("all")}
</label>
</div>
);

View file

@ -12,9 +12,8 @@ import {
maxUploadImages,
relTags,
} from "../../config";
import { i18n } from "../../i18next";
import { customEmojisLookup, mdToHtml, setupTribute } from "../../markdown";
import { HttpService, UserService } from "../../services";
import { HttpService, I18NextService, UserService } from "../../services";
import { setupTippy } from "../../tippy";
import { pictrsDeleteToast, toast } from "../../toast";
import { EmojiPicker } from "./emoji-picker";
@ -129,7 +128,7 @@ export class MarkdownTextArea extends Component<
// TODO add these prompts back in at some point
// <Prompt
// when={!this.props.hideNavigationWarnings && this.state.content}
// message={i18n.t("block_leaving")}
// message={I18NextService.i18n.t("block_leaving")}
// />
return (
<form
@ -161,7 +160,7 @@ export class MarkdownTextArea extends Component<
className={`mb-0 ${
UserService.Instance.myUserInfo && "pointer"
}`}
data-tippy-content={i18n.t("upload_image")}
data-tippy-content={I18NextService.i18n.t("upload_image")}
>
{this.state.imageUploadStatus ? (
<Spinner />
@ -199,7 +198,7 @@ export class MarkdownTextArea extends Component<
<a
href={markdownHelpUrl}
className="btn btn-sm text-muted font-weight-bold"
title={i18n.t("formatting_help")}
title={I18NextService.i18n.t("formatting_help")}
rel={relTags}
>
<Icon icon="help-circle" classes="icon-inline" />
@ -241,15 +240,17 @@ export class MarkdownTextArea extends Component<
animated
value={this.state.imageUploadStatus.uploaded}
max={this.state.imageUploadStatus.total}
text={i18n.t("pictures_uploded_progess", {
text={
I18NextService.i18n.t("pictures_uploded_progess", {
uploaded: this.state.imageUploadStatus.uploaded,
total: this.state.imageUploadStatus.total,
})}
}) ?? undefined
}
/>
)}
</div>
<label className="visually-hidden" htmlFor={this.id}>
{i18n.t("body")}
{I18NextService.i18n.t("body")}
</label>
</div>
</div>
@ -290,7 +291,7 @@ export class MarkdownTextArea extends Component<
className="btn btn-sm btn-secondary ms-2"
onClick={linkEvent(this, this.handleReplyCancel)}
>
{i18n.t("cancel")}
{I18NextService.i18n.t("cancel")}
</button>
)}
{this.state.content && (
@ -300,7 +301,9 @@ export class MarkdownTextArea extends Component<
}`}
onClick={linkEvent(this, this.handlePreviewToggle)}
>
{this.state.previewMode ? i18n.t("edit") : i18n.t("preview")}
{this.state.previewMode
? I18NextService.i18n.t("edit")
: I18NextService.i18n.t("preview")}
</button>
)}
</div>
@ -332,8 +335,8 @@ export class MarkdownTextArea extends Component<
return (
<button
className="btn btn-sm text-muted"
data-tippy-content={i18n.t(type)}
aria-label={i18n.t(type)}
data-tippy-content={I18NextService.i18n.t(type)}
aria-label={I18NextService.i18n.t(type)}
onClick={linkEvent(this, handleClick)}
disabled={this.isDisabled}
>
@ -376,7 +379,7 @@ export class MarkdownTextArea extends Component<
if (files.length > maxUploadImages) {
toast(
i18n.t("too_many_images_upload", {
I18NextService.i18n.t("too_many_images_upload", {
count: Number(maxUploadImages),
formattedCount: numToSI(maxUploadImages),
}),
@ -677,7 +680,7 @@ export class MarkdownTextArea extends Component<
handleInsertSpoiler(i: MarkdownTextArea, event: any) {
event.preventDefault();
const beforeChars = `\n::: spoiler ${i18n.t("spoiler")}\n`;
const beforeChars = `\n::: spoiler ${I18NextService.i18n.t("spoiler")}\n`;
const afterChars = "\n:::\n";
i.simpleSurroundBeforeAfter(beforeChars, afterChars);
}

View file

@ -1,7 +1,7 @@
import { capitalizeFirstLetter } from "@utils/helpers";
import { Component } from "inferno";
import moment from "moment";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Icon } from "./icon";
interface MomentTimeProps {
@ -15,18 +15,18 @@ export class MomentTime extends Component<MomentTimeProps, any> {
constructor(props: any, context: any) {
super(props, context);
moment.locale([...i18n.languages]);
moment.locale([...I18NextService.i18n.languages]);
}
createdAndModifiedTimes() {
const updated = this.props.updated;
let line = `${capitalizeFirstLetter(i18n.t("created"))}: ${this.format(
this.props.published
)}`;
let line = `${capitalizeFirstLetter(
I18NextService.i18n.t("created")
)}: ${this.format(this.props.published)}`;
if (updated) {
line += `\n\n\n${capitalizeFirstLetter(i18n.t("modified"))} ${this.format(
updated
)}`;
line += `\n\n\n${capitalizeFirstLetter(
I18NextService.i18n.t("modified")
)} ${this.format(updated)}`;
}
return line;
}

View file

@ -1,5 +1,5 @@
import { Component } from "inferno";
import { i18n } from "../../../shared/i18next";
import { I18NextService } from "../../services";
export interface IPromptProps {
when: boolean;
@ -14,7 +14,7 @@ export default class NavigationPrompt extends Component<IPromptProps, any> {
}
this.unblock = this.context.router.history.block(tx => {
if (window.confirm(i18n.t("block_leaving"))) {
if (window.confirm(I18NextService.i18n.t("block_leaving") ?? undefined)) {
this.unblock();
tx.retry();
}

View file

@ -1,5 +1,5 @@
import { Component, linkEvent } from "inferno";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
interface PaginatorProps {
page: number;
@ -18,13 +18,13 @@ export class Paginator extends Component<PaginatorProps, any> {
disabled={this.props.page == 1}
onClick={linkEvent(this, this.handlePrev)}
>
{i18n.t("prev")}
{I18NextService.i18n.t("prev")}
</button>
<button
className="btn btn-secondary"
onClick={linkEvent(this, this.handleNext)}
>
{i18n.t("next")}
{I18NextService.i18n.t("next")}
</button>
</div>
);

View file

@ -5,8 +5,8 @@ import {
ApproveRegistrationApplication,
RegistrationApplicationView,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { I18NextService } from "../../services";
import { PersonListing } from "../person/person-listing";
import { Spinner } from "./icon";
import { MarkdownTextArea } from "./markdown-textarea";
@ -61,12 +61,14 @@ export class RegistrationApplication extends Component<
return (
<div className="registration-application">
<div>
{i18n.t("applicant")}: <PersonListing person={a.creator} />
{I18NextService.i18n.t("applicant")}:{" "}
<PersonListing person={a.creator} />
</div>
<div>
{i18n.t("created")}: <MomentTime showAgo published={ra.published} />
{I18NextService.i18n.t("created")}:{" "}
<MomentTime showAgo published={ra.published} />
</div>
<div>{i18n.t("answer")}:</div>
<div>{I18NextService.i18n.t("answer")}:</div>
<div className="md-div" dangerouslySetInnerHTML={mdToHtml(ra.answer)} />
{a.admin && (
@ -84,7 +86,7 @@ export class RegistrationApplication extends Component<
</T>
{ra.deny_reason && (
<div>
{i18n.t("deny_reason")}:{" "}
{I18NextService.i18n.t("deny_reason")}:{" "}
<div
className="md-div d-inline-flex"
dangerouslySetInnerHTML={mdToHtml(ra.deny_reason)}
@ -99,7 +101,7 @@ export class RegistrationApplication extends Component<
{this.state.denyExpanded && (
<div className="mb-3 row">
<label className="col-sm-2 col-form-label">
{i18n.t("deny_reason")}
{I18NextService.i18n.t("deny_reason")}
</label>
<div className="col-sm-10">
<MarkdownTextArea
@ -116,18 +118,26 @@ export class RegistrationApplication extends Component<
<button
className="btn btn-secondary me-2 my-2"
onClick={linkEvent(this, this.handleApprove)}
aria-label={i18n.t("approve")}
aria-label={I18NextService.i18n.t("approve")}
>
{this.state.approveLoading ? <Spinner /> : i18n.t("approve")}
{this.state.approveLoading ? (
<Spinner />
) : (
I18NextService.i18n.t("approve")
)}
</button>
)}
{(!ra.admin_id || (ra.admin_id && accepted)) && (
<button
className="btn btn-secondary me-2"
onClick={linkEvent(this, this.handleDeny)}
aria-label={i18n.t("deny")}
aria-label={I18NextService.i18n.t("deny")}
>
{this.state.denyLoading ? <Spinner /> : i18n.t("deny")}
{this.state.denyLoading ? (
<Spinner />
) : (
I18NextService.i18n.t("deny")
)}
</button>
)}
</div>

View file

@ -7,7 +7,7 @@ import {
linkEvent,
RefObject,
} from "inferno";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Icon, Spinner } from "./icon";
interface SearchableSelectProps {
@ -113,7 +113,7 @@ export class SearchableSelect extends Component<
ref={this.toggleButtonRef}
>
{loading
? `${i18n.t("loading")}${loadingEllipses}`
? `${I18NextService.i18n.t("loading")}${loadingEllipses}`
: options[selectedIndex].label}
</button>
<div
@ -131,7 +131,7 @@ export class SearchableSelect extends Component<
ref={this.searchInputRef}
onInput={linkEvent(this, handleSearch)}
value={searchText}
placeholder={`${i18n.t("search")}...`}
placeholder={`${I18NextService.i18n.t("search")}...`}
/>
</div>
{!loading &&

View file

@ -2,7 +2,7 @@ import { randomStr } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { SortType } from "lemmy-js-client";
import { relTags, sortingHelpUrl } from "../../config";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Icon } from "./icon";
interface SortSelectProps {
@ -41,46 +41,46 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
value={this.state.sort}
onChange={linkEvent(this, this.handleSortChange)}
className="sort-select form-select d-inline-block w-auto me-2"
aria-label={i18n.t("sort_type")}
aria-label={I18NextService.i18n.t("sort_type")}
>
<option disabled aria-hidden="true">
{i18n.t("sort_type")}
{I18NextService.i18n.t("sort_type")}
</option>
{!this.props.hideHot && [
<option key={"Hot"} value={"Hot"}>
{i18n.t("hot")}
{I18NextService.i18n.t("hot")}
</option>,
<option key={"Active"} value={"Active"}>
{i18n.t("active")}
{I18NextService.i18n.t("active")}
</option>,
]}
<option value={"New"}>{i18n.t("new")}</option>
<option value={"Old"}>{i18n.t("old")}</option>
<option value={"New"}>{I18NextService.i18n.t("new")}</option>
<option value={"Old"}>{I18NextService.i18n.t("old")}</option>
{!this.props.hideMostComments && [
<option key={"MostComments"} value={"MostComments"}>
{i18n.t("most_comments")}
{I18NextService.i18n.t("most_comments")}
</option>,
<option key={"NewComments"} value={"NewComments"}>
{i18n.t("new_comments")}
{I18NextService.i18n.t("new_comments")}
</option>,
]}
<option disabled aria-hidden="true">
</option>
<option value={"TopHour"}>{i18n.t("top_hour")}</option>
<option value={"TopSixHour"}>{i18n.t("top_six_hours")}</option>
<option value={"TopTwelveHour"}>{i18n.t("top_twelve_hours")}</option>
<option value={"TopDay"}>{i18n.t("top_day")}</option>
<option value={"TopWeek"}>{i18n.t("top_week")}</option>
<option value={"TopMonth"}>{i18n.t("top_month")}</option>
<option value={"TopYear"}>{i18n.t("top_year")}</option>
<option value={"TopAll"}>{i18n.t("top_all")}</option>
<option value={"TopHour"}>{I18NextService.i18n.t("top_hour")}</option>
<option value={"TopSixHour"}>{I18NextService.i18n.t("top_six_hours")}</option>
<option value={"TopTwelveHour"}>{I18NextService.i18n.t("top_twelve_hours")}</option>
<option value={"TopDay"}>{I18NextService.i18n.t("top_day")}</option>
<option value={"TopWeek"}>{I18NextService.i18n.t("top_week")}</option>
<option value={"TopMonth"}>{I18NextService.i18n.t("top_month")}</option>
<option value={"TopYear"}>{I18NextService.i18n.t("top_year")}</option>
<option value={"TopAll"}>{I18NextService.i18n.t("top_all")}</option>
</select>
<a
className="sort-select-icon text-muted"
href={sortingHelpUrl}
rel={relTags}
title={i18n.t("sorting_help")}
title={I18NextService.i18n.t("sorting_help")}
>
<Icon icon="help-circle" classes="icon-inline" />
</a>

View file

@ -21,9 +21,8 @@ import {
ListCommunitiesResponse,
ListingType,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";
@ -86,7 +85,7 @@ export class Communities extends Component<any, CommunitiesState> {
}
get documentTitle(): string {
return `${i18n.t("communities")} - ${
return `${I18NextService.i18n.t("communities")} - ${
this.state.siteRes.site_view.site.name
}`;
}
@ -103,7 +102,9 @@ export class Communities extends Component<any, CommunitiesState> {
const { listingType, page } = this.getCommunitiesQueryParams();
return (
<div>
<h1 className="h4">{i18n.t("list_of_communities")}</h1>
<h1 className="h4">
{I18NextService.i18n.t("list_of_communities")}
</h1>
<div className="row g-2 justify-content-between">
<div className="col-auto">
<ListingTypeSelect
@ -123,16 +124,19 @@ export class Communities extends Component<any, CommunitiesState> {
>
<thead className="pointer">
<tr>
<th>{i18n.t("name")}</th>
<th className="text-right">{i18n.t("subscribers")}</th>
<th>{I18NextService.i18n.t("name")}</th>
<th className="text-right">
{i18n.t("users")} / {i18n.t("month")}
{I18NextService.i18n.t("subscribers")}
</th>
<th className="text-right">
{I18NextService.i18n.t("users")} /{" "}
{I18NextService.i18n.t("month")}
</th>
<th className="text-right d-none d-lg-table-cell">
{i18n.t("posts")}
{I18NextService.i18n.t("posts")}
</th>
<th className="text-right d-none d-lg-table-cell">
{i18n.t("comments")}
{I18NextService.i18n.t("comments")}
</th>
<th></th>
</tr>
@ -169,7 +173,7 @@ export class Communities extends Component<any, CommunitiesState> {
this.handleFollow
)}
>
{i18n.t("unsubscribe")}
{I18NextService.i18n.t("unsubscribe")}
</button>
)}
{cv.subscribed === "NotSubscribed" && (
@ -184,12 +188,12 @@ export class Communities extends Component<any, CommunitiesState> {
this.handleFollow
)}
>
{i18n.t("subscribe")}
{I18NextService.i18n.t("subscribe")}
</button>
)}
{cv.subscribed === "Pending" && (
<div className="text-warning d-inline-block">
{i18n.t("subscribe_pending")}
{I18NextService.i18n.t("subscribe_pending")}
</div>
)}
</td>
@ -230,7 +234,7 @@ export class Communities extends Component<any, CommunitiesState> {
id="communities-search"
className="form-control"
value={this.state.searchText}
placeholder={`${i18n.t("search")}...`}
placeholder={`${I18NextService.i18n.t("search")}...`}
onInput={linkEvent(this, this.handleSearchChange)}
required
minLength={3}
@ -238,10 +242,10 @@ export class Communities extends Component<any, CommunitiesState> {
</div>
<div className="col-auto">
<label className="visually-hidden" htmlFor="communities-search">
{i18n.t("search")}
{I18NextService.i18n.t("search")}
</label>
<button type="submit" className="btn btn-secondary">
<span>{i18n.t("search")}</span>
<span>{I18NextService.i18n.t("search")}</span>
</button>
</div>
</form>

View file

@ -7,7 +7,7 @@ import {
EditCommunity,
Language,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Icon, Spinner } from "../common/icon";
import { ImageUploadForm } from "../common/image-upload-form";
import { LanguageSelect } from "../common/language-select";
@ -107,10 +107,10 @@ export class CommunityForm extends Component<
className="col-12 col-sm-2 col-form-label"
htmlFor="community-name"
>
{i18n.t("name")}
{I18NextService.i18n.t("name")}
<span
className="position-absolute pointer unselectable ms-2 text-muted"
data-tippy-content={i18n.t("name_explain")}
data-tippy-content={I18NextService.i18n.t("name_explain")}
>
<Icon icon="help-circle" classes="icon-inline" />
</span>
@ -125,7 +125,7 @@ export class CommunityForm extends Component<
required
minLength={3}
pattern="[a-z0-9_]+"
title={i18n.t("community_reqs")}
title={I18NextService.i18n.t("community_reqs")}
/>
</div>
</div>
@ -135,10 +135,10 @@ export class CommunityForm extends Component<
className="col-12 col-sm-2 col-form-label"
htmlFor="community-title"
>
{i18n.t("display_name")}
{I18NextService.i18n.t("display_name")}
<span
className="position-absolute pointer unselectable ms-2 text-muted"
data-tippy-content={i18n.t("display_name_explain")}
data-tippy-content={I18NextService.i18n.t("display_name_explain")}
>
<Icon icon="help-circle" classes="icon-inline" />
</span>
@ -158,11 +158,11 @@ export class CommunityForm extends Component<
</div>
<div className="mb-3 row">
<label className="col-12 col-sm-2 col-form-label">
{i18n.t("icon")}
{I18NextService.i18n.t("icon")}
</label>
<div className="col-12 col-sm-10">
<ImageUploadForm
uploadTitle={i18n.t("upload_icon")}
uploadTitle={I18NextService.i18n.t("upload_icon")}
imageSrc={this.state.form.icon}
onUpload={this.handleIconUpload}
onRemove={this.handleIconRemove}
@ -172,11 +172,11 @@ export class CommunityForm extends Component<
</div>
<div className="mb-3 row">
<label className="col-12 col-sm-2 col-form-label">
{i18n.t("banner")}
{I18NextService.i18n.t("banner")}
</label>
<div className="col-12 col-sm-10">
<ImageUploadForm
uploadTitle={i18n.t("upload_banner")}
uploadTitle={I18NextService.i18n.t("upload_banner")}
imageSrc={this.state.form.banner}
onUpload={this.handleBannerUpload}
onRemove={this.handleBannerRemove}
@ -185,12 +185,12 @@ export class CommunityForm extends Component<
</div>
<div className="mb-3 row">
<label className="col-12 col-sm-2 col-form-label" htmlFor={this.id}>
{i18n.t("sidebar")}
{I18NextService.i18n.t("sidebar")}
</label>
<div className="col-12 col-sm-10">
<MarkdownTextArea
initialContent={this.state.form.description}
placeholder={i18n.t("description")}
placeholder={I18NextService.i18n.t("description") ?? undefined}
onContentChange={this.handleCommunityDescriptionChange}
hideNavigationWarnings
allLanguages={[]}
@ -202,7 +202,7 @@ export class CommunityForm extends Component<
{this.props.enableNsfw && (
<div className="mb-3 row">
<legend className="col-form-label col-sm-2 pt-0">
{i18n.t("nsfw")}
{I18NextService.i18n.t("nsfw")}
</legend>
<div className="col-10">
<div className="form-check">
@ -219,7 +219,7 @@ export class CommunityForm extends Component<
)}
<div className="mb-3 row">
<legend className="col-form-label col-6 pt-0">
{i18n.t("only_mods_can_post_in_community")}
{I18NextService.i18n.t("only_mods_can_post_in_community")}
</legend>
<div className="col-6">
<div className="form-check">
@ -254,9 +254,9 @@ export class CommunityForm extends Component<
{this.props.loading ? (
<Spinner />
) : this.props.community_view ? (
capitalizeFirstLetter(i18n.t("save"))
capitalizeFirstLetter(I18NextService.i18n.t("save"))
) : (
capitalizeFirstLetter(i18n.t("create"))
capitalizeFirstLetter(I18NextService.i18n.t("create"))
)}
</button>
{this.props.community_view && (
@ -265,7 +265,7 @@ export class CommunityForm extends Component<
className="btn btn-secondary"
onClick={linkEvent(this, this.handleCancel)}
>
{i18n.t("cancel")}
{I18NextService.i18n.t("cancel")}
</button>
)}
</div>

View file

@ -78,14 +78,12 @@ import {
TransferCommunity,
} from "lemmy-js-client";
import { fetchLimit, relTags } from "../../config";
import { i18n } from "../../i18next";
import {
CommentViewType,
DataType,
InitialFetchRequest,
} from "../../interfaces";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
@ -331,7 +329,7 @@ export class Community extends Component<
className="btn btn-secondary d-inline-block mb-2 me-3"
onClick={linkEvent(this, this.handleShowSidebarMobile)}
>
{i18n.t("sidebar")}{" "}
{I18NextService.i18n.t("sidebar")}{" "}
<Icon
icon={
this.state.showSidebarMobile
@ -758,14 +756,14 @@ export class Community extends Component<
async handleCommentReport(form: CreateCommentReport) {
const reportRes = await HttpService.client.createCommentReport(form);
if (reportRes.state == "success") {
toast(i18n.t("report_created"));
toast(I18NextService.i18n.t("report_created"));
}
}
async handlePostReport(form: CreatePostReport) {
const reportRes = await HttpService.client.createPostReport(form);
if (reportRes.state == "success") {
toast(i18n.t("report_created"));
toast(I18NextService.i18n.t("report_created"));
}
}
@ -791,7 +789,7 @@ export class Community extends Component<
const transferCommunityRes = await HttpService.client.transferCommunity(
form
);
toast(i18n.t("transfer_community"));
toast(I18NextService.i18n.t("transfer_community"));
this.updateCommunityFull(transferCommunityRes);
}
@ -880,7 +878,7 @@ export class Community extends Component<
purgeItem(purgeRes: RequestState<PurgeItemResponse>) {
if (purgeRes.state == "success") {
toast(i18n.t("purge_success"));
toast(I18NextService.i18n.t("purge_success"));
this.context.router.history.push(`/`);
}
}

View file

@ -4,8 +4,7 @@ import {
CreateCommunity as CreateCommunityI,
GetSiteResponse,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { HttpService } from "../../services/HttpService";
import { HttpService, I18NextService } from "../../services";
import { HtmlTags } from "../common/html-tags";
import { CommunityForm } from "./community-form";
@ -26,7 +25,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
}
get documentTitle(): string {
return `${i18n.t("create_community")} - ${
return `${I18NextService.i18n.t("create_community")} - ${
this.state.siteRes.site_view.site.name
}`;
}
@ -40,7 +39,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
/>
<div className="row">
<div className="col-12 col-lg-6 offset-lg-3 mb-4">
<h5>{i18n.t("create_community")}</h5>
<h5>{I18NextService.i18n.t("create_community")}</h5>
<CommunityForm
onUpsertCommunity={this.handleCommunityCreate}
enableNsfw={enableNsfw(this.state.siteRes)}

View file

@ -17,9 +17,8 @@ import {
PurgeCommunity,
RemoveCommunity,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { Badges } from "../common/badges";
import { BannerIconHeader } from "../common/banner-icon-header";
import { Icon, PurgeWarning, Spinner } from "../common/icon";
@ -187,7 +186,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
) : (
<>
<Icon icon="check" classes="icon-inline text-success me-1" />
{i18n.t("joined")}
{I18NextService.i18n.t("joined")}
</>
)}
</button>
@ -200,23 +199,23 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
{this.state.followCommunityLoading ? (
<Spinner />
) : (
i18n.t("subscribe_pending")
I18NextService.i18n.t("subscribe_pending")
)}
</button>
)}
{community.removed && (
<small className="me-2 text-muted font-italic">
{i18n.t("removed")}
{I18NextService.i18n.t("removed")}
</small>
)}
{community.deleted && (
<small className="me-2 text-muted font-italic">
{i18n.t("deleted")}
{I18NextService.i18n.t("deleted")}
</small>
)}
{community.nsfw && (
<small className="me-2 text-muted font-italic">
{i18n.t("nsfw")}
{I18NextService.i18n.t("nsfw")}
</small>
)}
</h5>
@ -234,7 +233,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
mods() {
return (
<ul className="list-inline small">
<li className="list-inline-item">{i18n.t("mods")}: </li>
<li className="list-inline-item">{I18NextService.i18n.t("mods")}: </li>
{this.props.moderators.map(mod => (
<li key={mod.moderator.id} className="list-inline-item">
<PersonListing person={mod.moderator} />
@ -253,7 +252,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
}`}
to={`/create_post?communityId=${cv.community.id}`}
>
{i18n.t("create_a_post")}
{I18NextService.i18n.t("create_a_post")}
</Link>
);
}
@ -270,7 +269,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
{this.state.followCommunityLoading ? (
<Spinner />
) : (
i18n.t("subscribe")
I18NextService.i18n.t("subscribe")
)}
</button>
)}
@ -288,7 +287,9 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
className="btn btn-danger d-block mb-2 w-100"
onClick={linkEvent(this, this.handleBlockCommunity)}
>
{i18n.t(blocked ? "unblock_community" : "block_community")}
{I18NextService.i18n.t(
blocked ? "unblock_community" : "block_community"
)}
</button>
)}
</>
@ -315,8 +316,8 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<button
className="btn btn-link text-muted d-inline-block"
onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t("edit")}
aria-label={i18n.t("edit")}
data-tippy-content={I18NextService.i18n.t("edit")}
aria-label={I18NextService.i18n.t("edit")}
>
<Icon icon="edit" classes="icon-inline" />
</button>
@ -331,20 +332,20 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
this.handleShowConfirmLeaveModTeamClick
)}
>
{i18n.t("leave_mod_team")}
{I18NextService.i18n.t("leave_mod_team")}
</button>
</li>
) : (
<>
<li className="list-inline-item-action">
{i18n.t("are_you_sure")}
{I18NextService.i18n.t("are_you_sure")}
</li>
<li className="list-inline-item-action">
<button
className="btn btn-link text-muted d-inline-block"
onClick={linkEvent(this, this.handleLeaveModTeam)}
>
{i18n.t("yes")}
{I18NextService.i18n.t("yes")}
</button>
</li>
<li className="list-inline-item-action">
@ -355,7 +356,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
this.handleCancelLeaveModTeamClick
)}
>
{i18n.t("no")}
{I18NextService.i18n.t("no")}
</button>
</li>
</>
@ -367,13 +368,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
onClick={linkEvent(this, this.handleDeleteCommunity)}
data-tippy-content={
!community_view.community.deleted
? i18n.t("delete")
: i18n.t("restore")
? I18NextService.i18n.t("delete")
: I18NextService.i18n.t("restore")
}
aria-label={
!community_view.community.deleted
? i18n.t("delete")
: i18n.t("restore")
? I18NextService.i18n.t("delete")
: I18NextService.i18n.t("restore")
}
>
{this.state.deleteCommunityLoading ? (
@ -398,7 +399,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
className="btn btn-link text-muted d-inline-block"
onClick={linkEvent(this, this.handleModRemoveShow)}
>
{i18n.t("remove")}
{I18NextService.i18n.t("remove")}
</button>
) : (
<button
@ -408,16 +409,16 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
{this.state.removeCommunityLoading ? (
<Spinner />
) : (
i18n.t("restore")
I18NextService.i18n.t("restore")
)}
</button>
)}
<button
className="btn btn-link text-muted d-inline-block"
onClick={linkEvent(this, this.handlePurgeCommunityShow)}
aria-label={i18n.t("purge_community")}
aria-label={I18NextService.i18n.t("purge_community")}
>
{i18n.t("purge_community")}
{I18NextService.i18n.t("purge_community")}
</button>
</li>
)}
@ -426,13 +427,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<form onSubmit={linkEvent(this, this.handleRemoveCommunity)}>
<div className="input-group mb-3">
<label className="col-form-label" htmlFor="remove-reason">
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id="remove-reason"
className="form-control me-2"
placeholder={i18n.t("optional")}
placeholder={I18NextService.i18n.t("optional")}
value={this.state.removeReason}
onInput={linkEvent(this, this.handleModRemoveReasonChange)}
/>
@ -440,14 +441,14 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
{/* TODO hold off on expires for now */}
{/* <div class="mb-3 row"> */}
{/* <label class="col-form-label">Expires</label> */}
{/* <input type="date" class="form-control me-2" placeholder={i18n.t('expires')} value={this.state.removeExpires} onInput={linkEvent(this, this.handleModRemoveExpiresChange)} /> */}
{/* <input type="date" class="form-control me-2" placeholder={I18NextService.i18n.t('expires')} value={this.state.removeExpires} onInput={linkEvent(this, this.handleModRemoveExpiresChange)} /> */}
{/* </div> */}
<div className="input-group mb-3">
<button type="submit" className="btn btn-secondary">
{this.state.removeCommunityLoading ? (
<Spinner />
) : (
i18n.t("remove_community")
I18NextService.i18n.t("remove_community")
)}
</button>
</div>
@ -460,13 +461,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
</div>
<div className="input-group mb-3">
<label className="visually-hidden" htmlFor="purge-reason">
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id="purge-reason"
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
value={this.state.purgeReason}
onInput={linkEvent(this, this.handlePurgeReasonChange)}
/>
@ -478,9 +479,9 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<button
type="submit"
className="btn btn-secondary"
aria-label={i18n.t("purge_community")}
aria-label={I18NextService.i18n.t("purge_community")}
>
{i18n.t("purge_community")}
{I18NextService.i18n.t("purge_community")}
</button>
)}
</div>

View file

@ -18,10 +18,9 @@ import {
GetSiteResponse,
PersonView,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { removeFromEmojiDataModel, updateEmojiDataModel } from "../../markdown";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
@ -108,7 +107,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
}
get documentTitle(): string {
return `${i18n.t("admin_settings")} - ${
return `${I18NextService.i18n.t("admin_settings")} - ${
this.state.siteRes.site_view.site.name
}`;
}
@ -129,7 +128,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
tabs={[
{
key: "site",
label: i18n.t("site"),
label: I18NextService.i18n.t("site"),
getNode: isSelected => (
<div
className={classNames("tab-pane show", {
@ -181,7 +180,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
},
{
key: "taglines",
label: i18n.t("taglines"),
label: I18NextService.i18n.t("taglines"),
getNode: isSelected => (
<div
className={classNames("tab-pane", {
@ -202,7 +201,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
},
{
key: "emojis",
label: i18n.t("emojis"),
label: I18NextService.i18n.t("emojis"),
getNode: isSelected => (
<div
className={classNames("tab-pane", {
@ -253,7 +252,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
admins() {
return (
<>
<h5>{capitalizeFirstLetter(i18n.t("admins"))}</h5>
<h5>{capitalizeFirstLetter(I18NextService.i18n.t("admins"))}</h5>
<ul className="list-unstyled">
{this.state.siteRes.admins.map(admin => (
<li key={admin.person.id} className="list-inline-item">
@ -275,7 +274,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
{this.state.leaveAdminTeamRes.state == "loading" ? (
<Spinner />
) : (
i18n.t("leave_admin_team")
I18NextService.i18n.t("leave_admin_team")
)}
</button>
);
@ -293,7 +292,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
const bans = this.state.bannedRes.data.banned;
return (
<>
<h5>{i18n.t("banned_users")}</h5>
<h5>{I18NextService.i18n.t("banned_users")}</h5>
<ul className="list-unstyled">
{bans.map(banned => (
<li key={banned.person.id} className="list-inline-item">
@ -319,7 +318,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
s.siteRes.taglines = editRes.data.taglines;
return s;
});
toast(i18n.t("site_saved"));
toast(I18NextService.i18n.t("site_saved"));
}
this.setState({ loading: false });
@ -340,7 +339,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
});
if (this.state.leaveAdminTeamRes.state === "success") {
toast(i18n.t("left_admin_team"));
toast(I18NextService.i18n.t("left_admin_team"));
this.context.router.history.replace("/");
}
}

View file

@ -6,9 +6,8 @@ import {
EditCustomEmoji,
GetSiteResponse,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { customEmojisLookup } from "../../markdown";
import { HttpService } from "../../services/HttpService";
import { HttpService, I18NextService } from "../../services";
import { pictrsDeleteToast, toast } from "../../toast";
import { EmojiMart } from "../common/emoji-mart";
import { HtmlTags } from "../common/html-tags";
@ -66,7 +65,7 @@ export class EmojiForm extends Component<EmojiFormProps, EmojiFormState> {
this.handleEmojiClick = this.handleEmojiClick.bind(this);
}
get documentTitle(): string {
return i18n.t("custom_emojis");
return I18NextService.i18n.t("custom_emojis");
}
render() {
@ -76,7 +75,7 @@ export class EmojiForm extends Component<EmojiFormProps, EmojiFormState> {
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<h5 className="col-12">{i18n.t("custom_emojis")}</h5>
<h5 className="col-12">{I18NextService.i18n.t("custom_emojis")}</h5>
{customEmojisLookup.size > 0 && (
<div>
<EmojiMart
@ -89,15 +88,21 @@ export class EmojiForm extends Component<EmojiFormProps, EmojiFormState> {
<table id="emojis_table" className="table table-sm table-hover">
<thead className="pointer">
<tr>
<th>{i18n.t("column_emoji")}</th>
<th className="text-right">{i18n.t("column_shortcode")}</th>
<th className="text-right">{i18n.t("column_category")}</th>
<th className="text-right d-lg-table-cell d-none">
{i18n.t("column_imageurl")}
<th>{I18NextService.i18n.t("column_emoji")}</th>
<th className="text-right">
{I18NextService.i18n.t("column_shortcode")}
</th>
<th className="text-right">
{I18NextService.i18n.t("column_category")}
</th>
<th className="text-right d-lg-table-cell d-none">
{I18NextService.i18n.t("column_imageurl")}
</th>
<th className="text-right">
{I18NextService.i18n.t("column_alttext")}
</th>
<th className="text-right">{i18n.t("column_alttext")}</th>
<th className="text-right d-lg-table-cell">
{i18n.t("column_keywords")}
{I18NextService.i18n.t("column_keywords")}
</th>
<th style="width:121px"></th>
</tr>
@ -215,8 +220,8 @@ export class EmojiForm extends Component<EmojiFormProps, EmojiFormState> {
{ i: this, cv: cv },
this.handleEditEmojiClick
)}
data-tippy-content={i18n.t("save")}
aria-label={i18n.t("save")}
data-tippy-content={I18NextService.i18n.t("save")}
aria-label={I18NextService.i18n.t("save")}
disabled={
this.props.loading ||
!this.canEdit(cv) ||
@ -236,10 +241,10 @@ export class EmojiForm extends Component<EmojiFormProps, EmojiFormState> {
{ i: this, index: index, cv: cv },
this.handleDeleteEmojiClick
)}
data-tippy-content={i18n.t("delete")}
aria-label={i18n.t("delete")}
data-tippy-content={I18NextService.i18n.t("delete")}
aria-label={I18NextService.i18n.t("delete")}
disabled={this.props.loading}
title={i18n.t("delete")}
title={I18NextService.i18n.t("delete")}
>
<Icon
icon="trash"
@ -257,7 +262,7 @@ export class EmojiForm extends Component<EmojiFormProps, EmojiFormState> {
className="btn btn-sm btn-secondary me-2"
onClick={linkEvent(this, this.handleAddEmojiClick)}
>
{i18n.t("add_custom_emoji")}
{I18NextService.i18n.t("add_custom_emoji")}
</button>
<Paginator page={this.state.page} onChange={this.handlePageChange} />
@ -280,8 +285,8 @@ export class EmojiForm extends Component<EmojiFormProps, EmojiFormState> {
}
getEditTooltip(cv: CustomEmojiViewForm) {
if (this.canEdit(cv)) return i18n.t("save");
else return i18n.t("custom_emoji_save_validation");
if (this.canEdit(cv)) return I18NextService.i18n.t("save");
else return I18NextService.i18n.t("custom_emoji_save_validation");
}
handlePageChange(page: number) {

View file

@ -73,15 +73,13 @@ import {
TransferCommunity,
} from "lemmy-js-client";
import { fetchLimit, relTags, trendingFetchLimit } from "../../config";
import { i18n } from "../../i18next";
import {
CommentViewType,
DataType,
InitialFetchRequest,
} from "../../interfaces";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
@ -197,7 +195,7 @@ const MobileButton = ({
className="btn btn-secondary d-inline-block mb-2 me-3"
onClick={onClick}
>
{i18n.t(textKey)}{" "}
{I18NextService.i18n.t(textKey)}{" "}
<Icon icon={show ? `minus-square` : `plus-square`} classes="icon-inline" />
</button>
);
@ -210,7 +208,7 @@ const LinkButton = ({
translationKey: NoOptionI18nKeys;
}) => (
<Link className="btn btn-secondary d-block" to={path}>
{i18n.t(translationKey)}
{I18NextService.i18n.t(translationKey)}
</Link>
);
@ -565,10 +563,14 @@ export class Home extends Component<any, HomeState> {
className="btn btn-sm text-muted"
onClick={linkEvent(this, this.handleCollapseSubscribe)}
aria-label={
subscribedCollapsed ? i18n.t("expand") : i18n.t("collapse")
subscribedCollapsed
? I18NextService.i18n.t("expand")
: I18NextService.i18n.t("collapse")
}
data-tippy-content={
subscribedCollapsed ? i18n.t("expand") : i18n.t("collapse")
subscribedCollapsed
? I18NextService.i18n.t("expand")
: I18NextService.i18n.t("collapse")
}
aria-expanded="true"
aria-controls="sidebarSubscribedBody"
@ -932,14 +934,14 @@ export class Home extends Component<any, HomeState> {
async handleCommentReport(form: CreateCommentReport) {
const reportRes = await HttpService.client.createCommentReport(form);
if (reportRes.state == "success") {
toast(i18n.t("report_created"));
toast(I18NextService.i18n.t("report_created"));
}
}
async handlePostReport(form: CreatePostReport) {
const reportRes = await HttpService.client.createPostReport(form);
if (reportRes.state == "success") {
toast(i18n.t("report_created"));
toast(I18NextService.i18n.t("report_created"));
}
}
@ -963,7 +965,7 @@ export class Home extends Component<any, HomeState> {
async handleTransferCommunity(form: TransferCommunity) {
await HttpService.client.transferCommunity(form);
toast(i18n.t("transfer_community"));
toast(I18NextService.i18n.t("transfer_community"));
}
async handleCommentReplyRead(form: MarkCommentReplyAsRead) {
@ -1030,7 +1032,7 @@ export class Home extends Component<any, HomeState> {
purgeItem(purgeRes: RequestState<PurgeItemResponse>) {
if (purgeRes.state == "success") {
toast(i18n.t("purge_success"));
toast(I18NextService.i18n.t("purge_success"));
this.context.router.history.push(`/`);
}
}

View file

@ -7,9 +7,8 @@ import {
Instance,
} from "lemmy-js-client";
import { relTags } from "../../config";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";
@ -70,7 +69,9 @@ export class Instances extends Component<any, InstancesState> {
}
get documentTitle(): string {
return `${i18n.t("instances")} - ${this.state.siteRes.site_view.site.name}`;
return `${I18NextService.i18n.t("instances")} - ${
this.state.siteRes.site_view.site.name
}`;
}
renderInstances() {
@ -86,18 +87,18 @@ export class Instances extends Component<any, InstancesState> {
return instances ? (
<div className="row">
<div className="col-md-6">
<h5>{i18n.t("linked_instances")}</h5>
<h5>{I18NextService.i18n.t("linked_instances")}</h5>
{this.itemList(instances.linked)}
</div>
{instances.allowed && instances.allowed.length > 0 && (
<div className="col-md-6">
<h5>{i18n.t("allowed_instances")}</h5>
<h5>{I18NextService.i18n.t("allowed_instances")}</h5>
{this.itemList(instances.allowed)}
</div>
)}
{instances.blocked && instances.blocked.length > 0 && (
<div className="col-md-6">
<h5>{i18n.t("blocked_instances")}</h5>
<h5>{I18NextService.i18n.t("blocked_instances")}</h5>
{this.itemList(instances.blocked)}
</div>
)}
@ -127,9 +128,9 @@ export class Instances extends Component<any, InstancesState> {
<table id="instances_table" className="table table-sm table-hover">
<thead className="pointer">
<tr>
<th>{i18n.t("name")}</th>
<th>{i18n.t("software")}</th>
<th>{i18n.t("version")}</th>
<th>{I18NextService.i18n.t("name")}</th>
<th>{I18NextService.i18n.t("software")}</th>
<th>{I18NextService.i18n.t("version")}</th>
</tr>
</thead>
<tbody>
@ -148,7 +149,7 @@ export class Instances extends Component<any, InstancesState> {
</table>
</div>
) : (
<div>{i18n.t("none_found")}</div>
<div>{I18NextService.i18n.t("none_found")}</div>
);
}
}

View file

@ -1,8 +1,8 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno";
import { GetSiteResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { I18NextService } from "../../services";
import { HtmlTags } from "../common/html-tags";
interface LegalState {
@ -20,7 +20,7 @@ export class Legal extends Component<any, LegalState> {
}
get documentTitle(): string {
return i18n.t("legal_information");
return I18NextService.i18n.t("legal_information");
}
render() {

View file

@ -3,8 +3,7 @@ import { isBrowser } from "@utils/browser";
import { validEmail } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { GetSiteResponse, LoginResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
@ -43,7 +42,9 @@ export class Login extends Component<any, State> {
}
get documentTitle(): string {
return `${i18n.t("login")} - ${this.state.siteRes.site_view.site.name}`;
return `${I18NextService.i18n.t("login")} - ${
this.state.siteRes.site_view.site.name
}`;
}
get isLemmyMl(): boolean {
@ -68,13 +69,13 @@ export class Login extends Component<any, State> {
return (
<div>
<form onSubmit={linkEvent(this, this.handleLoginSubmit)}>
<h5>{i18n.t("login")}</h5>
<h5>{I18NextService.i18n.t("login")}</h5>
<div className="mb-3 row">
<label
className="col-sm-2 col-form-label"
htmlFor="login-email-or-username"
>
{i18n.t("email_or_username")}
{I18NextService.i18n.t("email_or_username")}
</label>
<div className="col-sm-10">
<input
@ -91,7 +92,7 @@ export class Login extends Component<any, State> {
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="login-password">
{i18n.t("password")}
{I18NextService.i18n.t("password")}
</label>
<div className="col-sm-10">
<input
@ -112,9 +113,9 @@ export class Login extends Component<any, State> {
!!this.state.form.username_or_email &&
!validEmail(this.state.form.username_or_email)
}
title={i18n.t("no_password_reset")}
title={I18NextService.i18n.t("no_password_reset")}
>
{i18n.t("forgot_password")}
{I18NextService.i18n.t("forgot_password")}
</button>
</div>
</div>
@ -124,7 +125,7 @@ export class Login extends Component<any, State> {
className="col-sm-6 col-form-label"
htmlFor="login-totp-token"
>
{i18n.t("two_factor_token")}
{I18NextService.i18n.t("two_factor_token")}
</label>
<div className="col-sm-6">
<input
@ -146,7 +147,7 @@ export class Login extends Component<any, State> {
{this.state.loginRes.state == "loading" ? (
<Spinner />
) : (
i18n.t("login")
I18NextService.i18n.t("login")
)}
</button>
</div>
@ -172,7 +173,7 @@ export class Login extends Component<any, State> {
case "failed": {
if (loginRes.msg === "missing_totp_token") {
i.setState({ showTotp: true });
toast(i18n.t("enter_two_factor_code"), "info");
toast(I18NextService.i18n.t("enter_two_factor_code"), "info");
}
i.setState({ loginRes: { state: "failed", msg: loginRes.msg } });
@ -220,7 +221,7 @@ export class Login extends Component<any, State> {
if (email) {
const res = await HttpService.client.passwordReset({ email });
if (res.state == "success") {
toast(i18n.t("reset_password_mail_sent"));
toast(I18NextService.i18n.t("reset_password_mail_sent"));
}
}
}

View file

@ -3,7 +3,7 @@ import { capitalizeFirstLetter } from "@utils/helpers";
import classNames from "classnames";
import { Component, FormEventHandler, linkEvent } from "inferno";
import { EditSite, LocalSiteRateLimit } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Spinner } from "../common/icon";
import Tabs from "../common/tabs";
@ -57,7 +57,9 @@ function RateLimits({
return (
<div role="tabpanel" className={classNames("mb-3 row", className)}>
<div className="col-md-6">
<label htmlFor="rate-limit">{i18n.t("rate_limit")}</label>
<label htmlFor="rate-limit">
{I18NextService.i18n.t("rate_limit")}
</label>
<input
type="number"
id="rate-limit"
@ -68,7 +70,9 @@ function RateLimits({
/>
</div>
<div className="col-md-6">
<label htmlFor="rate-limit-per-second">{i18n.t("per_second")}</label>
<label htmlFor="rate-limit-per-second">
{I18NextService.i18n.t("per_second")}
</label>
<input
type="number"
id="rate-limit-per-second"
@ -141,11 +145,11 @@ export default class RateLimitsForm extends Component<
className="rate-limit-form"
onSubmit={linkEvent(this, submitRateLimitForm)}
>
<h5>{i18n.t("rate_limit_header")}</h5>
<h5>{I18NextService.i18n.t("rate_limit_header")}</h5>
<Tabs
tabs={rateLimitTypes.map(rateLimitType => ({
key: rateLimitType,
label: i18n.t(`rate_limit_${rateLimitType}`),
label: I18NextService.i18n.t(`rate_limit_${rateLimitType}`),
getNode: isSelected => (
<RateLimits
className={classNames("tab-pane show", {
@ -176,7 +180,7 @@ export default class RateLimitsForm extends Component<
{this.props.loading ? (
<Spinner />
) : (
capitalizeFirstLetter(i18n.t("save"))
capitalizeFirstLetter(I18NextService.i18n.t("save"))
)}
</button>
</div>

View file

@ -7,8 +7,7 @@ import {
LoginResponse,
Register,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { Spinner } from "../common/icon";
import { SiteForm } from "./site-form";
@ -55,7 +54,7 @@ export class Setup extends Component<any, State> {
}
get documentTitle(): string {
return `${i18n.t("setup")} - Lemmy`;
return `${I18NextService.i18n.t("setup")} - Lemmy`;
}
render() {
@ -64,7 +63,7 @@ export class Setup extends Component<any, State> {
<Helmet title={this.documentTitle} />
<div className="row">
<div className="col-12 offset-lg-3 col-lg-6">
<h3>{i18n.t("lemmy_instance_setup")}</h3>
<h3>{I18NextService.i18n.t("lemmy_instance_setup")}</h3>
{!this.state.doneRegisteringUser ? (
this.registerUser()
) : (
@ -85,10 +84,10 @@ export class Setup extends Component<any, State> {
registerUser() {
return (
<form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
<h5>{i18n.t("setup_admin")}</h5>
<h5>{I18NextService.i18n.t("setup_admin")}</h5>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="username">
{i18n.t("username")}
{I18NextService.i18n.t("username")}
</label>
<div className="col-sm-10">
<input
@ -105,7 +104,7 @@ export class Setup extends Component<any, State> {
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="email">
{i18n.t("email")}
{I18NextService.i18n.t("email")}
</label>
<div className="col-sm-10">
@ -113,7 +112,7 @@ export class Setup extends Component<any, State> {
type="email"
id="email"
className="form-control"
placeholder={i18n.t("optional")}
placeholder={I18NextService.i18n.t("optional")}
value={this.state.form.email}
onInput={linkEvent(this, this.handleRegisterEmailChange)}
minLength={3}
@ -122,7 +121,7 @@ export class Setup extends Component<any, State> {
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="password">
{i18n.t("password")}
{I18NextService.i18n.t("password")}
</label>
<div className="col-sm-10">
<input
@ -140,7 +139,7 @@ export class Setup extends Component<any, State> {
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="verify-password">
{i18n.t("verify_password")}
{I18NextService.i18n.t("verify_password")}
</label>
<div className="col-sm-10">
<input
@ -162,7 +161,7 @@ export class Setup extends Component<any, State> {
{this.state.registerRes.state == "loading" ? (
<Spinner />
) : (
i18n.t("sign_up")
I18NextService.i18n.t("sign_up")
)}
</button>
</div>

View file

@ -13,9 +13,8 @@ import {
SiteView,
} from "lemmy-js-client";
import { joinLemmyUrl } from "../../config";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
@ -113,7 +112,7 @@ export class Signup extends Component<any, State> {
}
titleName(siteView: SiteView): string {
return i18n.t(
return I18NextService.i18n.t(
siteView.local_site.private_instance ? "apply_to_join" : "sign_up"
);
}
@ -159,7 +158,7 @@ export class Signup extends Component<any, State> {
className="col-sm-2 col-form-label"
htmlFor="register-username"
>
{i18n.t("username")}
{I18NextService.i18n.t("username")}
</label>
<div className="col-sm-10">
@ -172,14 +171,14 @@ export class Signup extends Component<any, State> {
required
minLength={3}
pattern="[a-zA-Z0-9_]+"
title={i18n.t("community_reqs")}
title={I18NextService.i18n.t("community_reqs")}
/>
</div>
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="register-email">
{i18n.t("email")}
{I18NextService.i18n.t("email")}
</label>
<div className="col-sm-10">
<input
@ -188,8 +187,8 @@ export class Signup extends Component<any, State> {
className="form-control"
placeholder={
siteView.local_site.require_email_verification
? i18n.t("required")
: i18n.t("optional")
? I18NextService.i18n.t("required")
: I18NextService.i18n.t("optional")
}
value={this.state.form.email}
autoComplete="email"
@ -202,7 +201,7 @@ export class Signup extends Component<any, State> {
!validEmail(this.state.form.email) && (
<div className="mt-2 mb-0 alert alert-warning" role="alert">
<Icon icon="alert-triangle" classes="icon-inline me-2" />
{i18n.t("no_password_reset")}
{I18NextService.i18n.t("no_password_reset")}
</div>
)}
</div>
@ -213,7 +212,7 @@ export class Signup extends Component<any, State> {
className="col-sm-2 col-form-label"
htmlFor="register-password"
>
{i18n.t("password")}
{I18NextService.i18n.t("password")}
</label>
<div className="col-sm-10">
<input
@ -229,7 +228,9 @@ export class Signup extends Component<any, State> {
/>
{this.state.form.password && (
<div className={this.passwordColorClass}>
{i18n.t(this.passwordStrength as NoOptionI18nKeys)}
{I18NextService.i18n.t(
this.passwordStrength as NoOptionI18nKeys
)}
</div>
)}
</div>
@ -240,7 +241,7 @@ export class Signup extends Component<any, State> {
className="col-sm-2 col-form-label"
htmlFor="register-verify-password"
>
{i18n.t("verify_password")}
{I18NextService.i18n.t("verify_password")}
</label>
<div className="col-sm-10">
<input
@ -262,7 +263,7 @@ export class Signup extends Component<any, State> {
<div className="offset-sm-2 col-sm-10">
<div className="mt-2 alert alert-warning" role="alert">
<Icon icon="alert-triangle" classes="icon-inline me-2" />
{i18n.t("fill_out_application")}
{I18NextService.i18n.t("fill_out_application")}
</div>
{siteView.local_site.application_question && (
<div
@ -280,7 +281,7 @@ export class Signup extends Component<any, State> {
className="col-sm-2 col-form-label"
htmlFor="application_answer"
>
{i18n.t("answer")}
{I18NextService.i18n.t("answer")}
</label>
<div className="col-sm-10">
<MarkdownTextArea
@ -306,7 +307,7 @@ export class Signup extends Component<any, State> {
onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}
/>
<label className="form-check-label" htmlFor="register-show-nsfw">
{i18n.t("show_nsfw")}
{I18NextService.i18n.t("show_nsfw")}
</label>
</div>
</div>
@ -345,12 +346,14 @@ export class Signup extends Component<any, State> {
return (
<div className="mb-3 row">
<label className="col-sm-2" htmlFor="register-captcha">
<span className="me-2">{i18n.t("enter_code")}</span>
<span className="me-2">
{I18NextService.i18n.t("enter_code")}
</span>
<button
type="button"
className="btn btn-secondary"
onClick={linkEvent(this, this.handleRegenCaptcha)}
aria-label={i18n.t("captcha")}
aria-label={I18NextService.i18n.t("captcha")}
>
<Icon icon="refresh-cw" classes="icon-refresh-cw" />
</button>
@ -384,13 +387,13 @@ export class Signup extends Component<any, State> {
className="rounded-top img-fluid"
src={this.captchaPngSrc(captchaRes)}
style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;"
alt={i18n.t("captcha")}
alt={I18NextService.i18n.t("captcha")}
/>
{captchaRes.wav && (
<button
className="rounded-bottom btn btn-sm btn-secondary d-block"
style="border-top-right-radius: 0; border-top-left-radius: 0;"
title={i18n.t("play_captcha_audio")}
title={I18NextService.i18n.t("play_captcha_audio")}
onClick={linkEvent(this, this.handleCaptchaPlay)}
type="button"
disabled={this.state.captchaPlaying}
@ -474,10 +477,10 @@ export class Signup extends Component<any, State> {
i.props.history.replace("/communities");
} else {
if (data.verify_email_sent) {
toast(i18n.t("verify_email_sent"));
toast(I18NextService.i18n.t("verify_email_sent"));
}
if (data.registration_created) {
toast(i18n.t("registration_application_sent"));
toast(I18NextService.i18n.t("registration_application_sent"));
}
i.props.history.push("/");
}

View file

@ -13,7 +13,7 @@ import {
Instance,
ListingType,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Icon, Spinner } from "../common/icon";
import { ImageUploadForm } from "../common/image-upload-form";
import { LanguageSelect } from "../common/language-select";
@ -136,12 +136,12 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
/>
<h5>{`${
siteSetup
? capitalizeFirstLetter(i18n.t("edit"))
: capitalizeFirstLetter(i18n.t("setup"))
} ${i18n.t("your_site")}`}</h5>
? capitalizeFirstLetter(I18NextService.i18n.t("edit"))
: capitalizeFirstLetter(I18NextService.i18n.t("setup"))
} ${I18NextService.i18n.t("your_site")}`}</h5>
<div className="mb-3 row">
<label className="col-12 col-form-label" htmlFor="create-site-name">
{i18n.t("name")}
{I18NextService.i18n.t("name")}
</label>
<div className="col-12">
<input
@ -157,9 +157,11 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
</div>
</div>
<div className="input-group mb-3">
<label className="me-2 col-form-label">{i18n.t("icon")}</label>
<label className="me-2 col-form-label">
{I18NextService.i18n.t("icon")}
</label>
<ImageUploadForm
uploadTitle={i18n.t("upload_icon")}
uploadTitle={I18NextService.i18n.t("upload_icon")}
imageSrc={this.state.siteForm.icon}
onUpload={this.handleIconUpload}
onRemove={this.handleIconRemove}
@ -167,9 +169,11 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
/>
</div>
<div className="input-group mb-3">
<label className="me-2 col-form-label">{i18n.t("banner")}</label>
<label className="me-2 col-form-label">
{I18NextService.i18n.t("banner")}
</label>
<ImageUploadForm
uploadTitle={i18n.t("upload_banner")}
uploadTitle={I18NextService.i18n.t("upload_banner")}
imageSrc={this.state.siteForm.banner}
onUpload={this.handleBannerUpload}
onRemove={this.handleBannerRemove}
@ -177,7 +181,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
</div>
<div className="mb-3 row">
<label className="col-12 col-form-label" htmlFor="site-desc">
{i18n.t("description")}
{I18NextService.i18n.t("description")}
</label>
<div className="col-12">
<input
@ -191,7 +195,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
</div>
</div>
<div className="mb-3 row">
<label className="col-12 col-form-label">{i18n.t("sidebar")}</label>
<label className="col-12 col-form-label">
{I18NextService.i18n.t("sidebar")}
</label>
<div className="col-12">
<MarkdownTextArea
initialContent={this.state.siteForm.sidebar}
@ -204,7 +210,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
</div>
<div className="mb-3 row">
<label className="col-12 col-form-label">
{i18n.t("legal_information")}
{I18NextService.i18n.t("legal_information")}
</label>
<div className="col-12">
<MarkdownTextArea
@ -230,7 +236,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-downvotes"
>
{i18n.t("enable_downvotes")}
{I18NextService.i18n.t("enable_downvotes")}
</label>
</div>
</div>
@ -249,7 +255,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-enable-nsfw"
>
{i18n.t("enable_nsfw")}
{I18NextService.i18n.t("enable_nsfw")}
</label>
</div>
</div>
@ -260,7 +266,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label me-2"
htmlFor="create-site-registration-mode"
>
{i18n.t("registration_mode")}
{I18NextService.i18n.t("registration_mode")}
</label>
<select
id="create-site-registration-mode"
@ -269,17 +275,21 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-select d-inline-block w-auto"
>
<option value={"RequireApplication"}>
{i18n.t("require_registration_application")}
{I18NextService.i18n.t("require_registration_application")}
</option>
<option value={"Open"}>
{I18NextService.i18n.t("open_registration")}
</option>
<option value={"Closed"}>
{I18NextService.i18n.t("close_registration")}
</option>
<option value={"Open"}>{i18n.t("open_registration")}</option>
<option value={"Closed"}>{i18n.t("close_registration")}</option>
</select>
</div>
</div>
{this.state.siteForm.registration_mode == "RequireApplication" && (
<div className="mb-3 row">
<label className="col-12 col-form-label">
{i18n.t("application_questionnaire")}
{I18NextService.i18n.t("application_questionnaire")}
</label>
<div className="col-12">
<MarkdownTextArea
@ -309,7 +319,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-community-creation-admin-only"
>
{i18n.t("community_creation_admin_only")}
{I18NextService.i18n.t("community_creation_admin_only")}
</label>
</div>
</div>
@ -331,7 +341,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-require-email-verification"
>
{i18n.t("require_email_verification")}
{I18NextService.i18n.t("require_email_verification")}
</label>
</div>
</div>
@ -353,7 +363,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-email-admins"
>
{i18n.t("application_email_admins")}
{I18NextService.i18n.t("application_email_admins")}
</label>
</div>
</div>
@ -372,7 +382,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-reports-email-admins"
>
{i18n.t("reports_email_admins")}
{I18NextService.i18n.t("reports_email_admins")}
</label>
</div>
</div>
@ -383,7 +393,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label me-2"
htmlFor="create-site-default-theme"
>
{i18n.t("theme")}
{I18NextService.i18n.t("theme")}
</label>
<select
id="create-site-default-theme"
@ -391,7 +401,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
onChange={linkEvent(this, this.handleSiteDefaultTheme)}
className="form-select d-inline-block w-auto"
>
<option value="browser">{i18n.t("browser_default")}</option>
<option value="browser">
{I18NextService.i18n.t("browser_default")}
</option>
{this.props.themeList?.map(theme => (
<option key={theme} value={theme}>
{theme}
@ -403,7 +415,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
{this.props.showLocal && (
<form className="mb-3 row">
<label className="col-sm-3 col-form-label">
{i18n.t("listing_type")}
{I18NextService.i18n.t("listing_type")}
</label>
<div className="col-sm-9">
<ListingTypeSelect
@ -429,7 +441,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-private-instance"
>
{i18n.t("private_instance")}
{I18NextService.i18n.t("private_instance")}
</label>
</div>
</div>
@ -448,7 +460,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-hide-modlog-mod-names"
>
{i18n.t("hide_modlog_mod_names")}
{I18NextService.i18n.t("hide_modlog_mod_names")}
</label>
</div>
</div>
@ -458,7 +470,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="col-12 col-form-label"
htmlFor="create-site-slur-filter-regex"
>
{i18n.t("slur_filter_regex")}
{I18NextService.i18n.t("slur_filter_regex")}
</label>
<div className="col-12">
<input
@ -485,7 +497,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="col-12 col-form-label"
htmlFor="create-site-actor-name"
>
{i18n.t("actor_name_max_length")}
{I18NextService.i18n.t("actor_name_max_length")}
</label>
<div className="col-12">
<input
@ -512,7 +524,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-federation-enabled"
>
{i18n.t("federation_enabled")}
{I18NextService.i18n.t("federation_enabled")}
</label>
</div>
</div>
@ -537,7 +549,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-federation-debug"
>
{i18n.t("federation_debug")}
{I18NextService.i18n.t("federation_debug")}
</label>
</div>
</div>
@ -547,7 +559,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="col-12 col-form-label"
htmlFor="create-site-federation-worker-count"
>
{i18n.t("federation_worker_count")}
{I18NextService.i18n.t("federation_worker_count")}
</label>
<div className="col-12">
<input
@ -579,7 +591,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label"
htmlFor="create-site-captcha-enabled"
>
{i18n.t("captcha_enabled")}
{I18NextService.i18n.t("captcha_enabled")}
</label>
</div>
</div>
@ -591,7 +603,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
className="form-check-label me-2"
htmlFor="create-site-captcha-difficulty"
>
{i18n.t("captcha_difficulty")}
{I18NextService.i18n.t("captcha_difficulty")}
</label>
<select
id="create-site-captcha-difficulty"
@ -599,9 +611,11 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
onChange={linkEvent(this, this.handleSiteCaptchaDifficulty)}
className="form-select d-inline-block w-auto"
>
<option value="easy">{i18n.t("easy")}</option>
<option value="medium">{i18n.t("medium")}</option>
<option value="hard">{i18n.t("hard")}</option>
<option value="easy">{I18NextService.i18n.t("easy")}</option>
<option value="medium">
{I18NextService.i18n.t("medium")}
</option>
<option value="hard">{I18NextService.i18n.t("hard")}</option>
</select>
</div>
</div>
@ -616,9 +630,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
{this.props.loading ? (
<Spinner />
) : siteSetup ? (
capitalizeFirstLetter(i18n.t("save"))
capitalizeFirstLetter(I18NextService.i18n.t("save"))
) : (
capitalizeFirstLetter(i18n.t("create"))
capitalizeFirstLetter(I18NextService.i18n.t("create"))
)}
</button>
</div>
@ -634,7 +648,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
return (
<div className="col-12 col-md-6">
<label className="col-form-label" htmlFor={id}>
{i18n.t(key)}
{I18NextService.i18n.t(key)}
</label>
<div className="d-flex justify-content-between align-items-center">
<input

View file

@ -1,7 +1,7 @@
import { Component, linkEvent } from "inferno";
import { PersonView, Site, SiteAggregates } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { I18NextService } from "../../services";
import { Badges } from "../common/badges";
import { BannerIconHeader } from "../common/banner-icon-header";
import { Icon } from "../common/icon";
@ -62,10 +62,14 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
className="btn btn-sm"
onClick={linkEvent(this, this.handleCollapseSidebar)}
aria-label={
this.state.collapsed ? i18n.t("expand") : i18n.t("collapse")
this.state.collapsed
? I18NextService.i18n.t("expand")
: I18NextService.i18n.t("collapse")
}
data-tippy-content={
this.state.collapsed ? i18n.t("expand") : i18n.t("collapse")
this.state.collapsed
? I18NextService.i18n.t("expand")
: I18NextService.i18n.t("collapse")
}
data-bs-toggle="collapse"
data-bs-target="#sidebarInfoBody"
@ -104,7 +108,7 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
admins(admins: PersonView[]) {
return (
<ul className="mt-1 list-inline small mb-0">
<li className="list-inline-item">{i18n.t("admins")}:</li>
<li className="list-inline-item">{I18NextService.i18n.t("admins")}:</li>
{admins.map(av => (
<li key={av.person.id} className="list-inline-item">
<PersonListing person={av.person} />

View file

@ -2,7 +2,7 @@ import { myAuthRequired } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers";
import { Component, InfernoMouseEvent, linkEvent } from "inferno";
import { EditSite, Tagline } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { HtmlTags } from "../common/html-tags";
import { Icon, Spinner } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea";
@ -27,7 +27,7 @@ export class TaglineForm extends Component<TaglineFormProps, TaglineFormState> {
super(props, context);
}
get documentTitle(): string {
return i18n.t("taglines");
return I18NextService.i18n.t("taglines");
}
render() {
@ -37,7 +37,7 @@ export class TaglineForm extends Component<TaglineFormProps, TaglineFormState> {
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<h5 className="col-12">{i18n.t("taglines")}</h5>
<h5 className="col-12">{I18NextService.i18n.t("taglines")}</h5>
<div className="table-responsive col-12">
<table id="taglines_table" className="table table-sm table-hover">
<thead className="pointer">
@ -68,8 +68,8 @@ export class TaglineForm extends Component<TaglineFormProps, TaglineFormState> {
{ i: this, index: index },
this.handleEditTaglineClick
)}
data-tippy-content={i18n.t("edit")}
aria-label={i18n.t("edit")}
data-tippy-content={I18NextService.i18n.t("edit")}
aria-label={I18NextService.i18n.t("edit")}
>
<Icon icon="edit" classes={`icon-inline`} />
</button>
@ -80,8 +80,8 @@ export class TaglineForm extends Component<TaglineFormProps, TaglineFormState> {
{ i: this, index: index },
this.handleDeleteTaglineClick
)}
data-tippy-content={i18n.t("delete")}
aria-label={i18n.t("delete")}
data-tippy-content={I18NextService.i18n.t("delete")}
aria-label={I18NextService.i18n.t("delete")}
>
<Icon icon="trash" classes={`icon-inline text-danger`} />
</button>
@ -96,7 +96,7 @@ export class TaglineForm extends Component<TaglineFormProps, TaglineFormState> {
className="btn btn-sm btn-secondary me-2"
onClick={linkEvent(this, this.handleAddTaglineClick)}
>
{i18n.t("add_tagline")}
{I18NextService.i18n.t("add_tagline")}
</button>
</div>
</div>
@ -111,7 +111,7 @@ export class TaglineForm extends Component<TaglineFormProps, TaglineFormState> {
{this.props.loading ? (
<Spinner />
) : (
capitalizeFirstLetter(i18n.t("save"))
capitalizeFirstLetter(I18NextService.i18n.t("save"))
)}
</button>
</div>

View file

@ -46,9 +46,8 @@ import {
} from "lemmy-js-client";
import moment from "moment";
import { fetchLimit } from "../config";
import { i18n } from "../i18next";
import { InitialFetchRequest } from "../interfaces";
import { FirstLoadService } from "../services/FirstLoadService";
import { FirstLoadService, I18NextService } from "../services";
import { HttpService, RequestState } from "../services/HttpService";
import { HtmlTags } from "./common/html-tags";
import { Icon, Spinner } from "./common/icon";
@ -586,14 +585,14 @@ const Filter = ({
}) => (
<div className="col-sm-6 mb-3">
<label className="mb-2" htmlFor={`filter-${filterType}`}>
{i18n.t(`filter_by_${filterType}` as NoOptionI18nKeys)}
{I18NextService.i18n.t(`filter_by_${filterType}` as NoOptionI18nKeys)}
</label>
<SearchableSelect
id={`filter-${filterType}`}
value={value ?? 0}
options={[
{
label: i18n.t("all"),
label: I18NextService.i18n.t("all"),
value: "0",
},
].concat(options)}
@ -724,8 +723,8 @@ export class Modlog extends Component<
this.isoData.site_res.admins.some(
({ person: { id } }) => id === person.id
)
? i18n.t("admin")
: i18n.t("mod");
? I18NextService.i18n.t("admin")
: I18NextService.i18n.t("mod");
}
get documentTitle(): string {
@ -770,7 +769,7 @@ export class Modlog extends Component<
>
/c/{this.state.communityRes.data.community_view.community.name}{" "}
</Link>
<span>{i18n.t("modlog")}</span>
<span>{I18NextService.i18n.t("modlog")}</span>
</h5>
)}
<div className="row mb-2">
@ -782,9 +781,9 @@ export class Modlog extends Component<
aria-label="action"
>
<option disabled aria-hidden="true">
{i18n.t("filter_by_action")}
{I18NextService.i18n.t("filter_by_action")}
</option>
<option value={"All"}>{i18n.t("all")}</option>
<option value={"All"}>{I18NextService.i18n.t("all")}</option>
<option value={"ModRemovePost"}>Removing Posts</option>
<option value={"ModLockPost"}>Locking Posts</option>
<option value={"ModFeaturePost"}>Featuring Posts</option>
@ -848,9 +847,9 @@ export class Modlog extends Component<
<table id="modlog_table" className="table table-sm table-hover">
<thead className="pointer">
<tr>
<th> {i18n.t("time")}</th>
<th>{i18n.t("mod")}</th>
<th>{i18n.t("action")}</th>
<th> {I18NextService.i18n.t("time")}</th>
<th>{I18NextService.i18n.t("mod")}</th>
<th>{I18NextService.i18n.t("action")}</th>
</tr>
</thead>
{this.combined}

View file

@ -1,5 +1,5 @@
import { Component } from "inferno";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Icon } from "../common/icon";
interface CakeDayProps {
@ -19,6 +19,8 @@ export class CakeDay extends Component<CakeDayProps, any> {
}
cakeDayTippy(): string {
return i18n.t("cake_day_info", { creator_name: this.props.creatorName });
return I18NextService.i18n.t("cake_day_info", {
creator_name: this.props.creatorName,
});
}
}

View file

@ -59,10 +59,8 @@ import {
TransferCommunity,
} from "lemmy-js-client";
import { fetchLimit, relTags } from "../../config";
import { i18n } from "../../i18next";
import { CommentViewType, InitialFetchRequest } from "../../interfaces";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { toast } from "../../toast";
import { CommentNodes } from "../comment/comment-nodes";
@ -187,9 +185,9 @@ export class Inbox extends Component<any, InboxState> {
get documentTitle(): string {
const mui = UserService.Instance.myUserInfo;
return mui
? `@${mui.local_user_view.person.name} ${i18n.t("inbox")} - ${
this.state.siteRes.site_view.site.name
}`
? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
"inbox"
)} - ${this.state.siteRes.site_view.site.name}`
: "";
}
@ -223,7 +221,7 @@ export class Inbox extends Component<any, InboxState> {
path={this.context.router.route.match.url}
/>
<h5 className="mb-2">
{i18n.t("inbox")}
{I18NextService.i18n.t("inbox")}
{inboxRss && (
<small>
<a href={inboxRss} title="RSS" rel={relTags}>
@ -245,7 +243,7 @@ export class Inbox extends Component<any, InboxState> {
{this.state.markAllAsReadRes.state == "loading" ? (
<Spinner />
) : (
i18n.t("mark_all_as_read")
I18NextService.i18n.t("mark_all_as_read")
)}
</button>
)}
@ -296,7 +294,7 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.unreadOrAll == UnreadOrAll.Unread}
onChange={linkEvent(this, this.handleUnreadOrAllChange)}
/>
{i18n.t("unread")}
{I18NextService.i18n.t("unread")}
</label>
<label
className={`btn btn-outline-secondary pointer
@ -310,7 +308,7 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.unreadOrAll == UnreadOrAll.All}
onChange={linkEvent(this, this.handleUnreadOrAllChange)}
/>
{i18n.t("all")}
{I18NextService.i18n.t("all")}
</label>
</div>
);
@ -331,7 +329,7 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.messageType == MessageType.All}
onChange={linkEvent(this, this.handleMessageTypeChange)}
/>
{i18n.t("all")}
{I18NextService.i18n.t("all")}
</label>
<label
className={`btn btn-outline-secondary pointer
@ -345,7 +343,7 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.messageType == MessageType.Replies}
onChange={linkEvent(this, this.handleMessageTypeChange)}
/>
{i18n.t("replies")}
{I18NextService.i18n.t("replies")}
</label>
<label
className={`btn btn-outline-secondary pointer
@ -359,7 +357,7 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.messageType == MessageType.Mentions}
onChange={linkEvent(this, this.handleMessageTypeChange)}
/>
{i18n.t("mentions")}
{I18NextService.i18n.t("mentions")}
</label>
<label
className={`btn btn-outline-secondary pointer
@ -373,7 +371,7 @@ export class Inbox extends Component<any, InboxState> {
checked={this.state.messageType == MessageType.Messages}
onChange={linkEvent(this, this.handleMessageTypeChange)}
/>
{i18n.t("messages")}
{I18NextService.i18n.t("messages")}
</label>
</div>
);
@ -826,7 +824,7 @@ export class Inbox extends Component<any, InboxState> {
const res = await HttpService.client.createComment(form);
if (res.state === "success") {
toast(i18n.t("reply_sent"));
toast(I18NextService.i18n.t("reply_sent"));
this.findAndUpdateComment(res);
}
@ -837,7 +835,7 @@ export class Inbox extends Component<any, InboxState> {
const res = await HttpService.client.editComment(form);
if (res.state === "success") {
toast(i18n.t("edit"));
toast(I18NextService.i18n.t("edit"));
this.findAndUpdateComment(res);
} else if (res.state === "failed") {
toast(res.msg, "danger");
@ -849,7 +847,7 @@ export class Inbox extends Component<any, InboxState> {
async handleDeleteComment(form: DeleteComment) {
const res = await HttpService.client.deleteComment(form);
if (res.state == "success") {
toast(i18n.t("deleted"));
toast(I18NextService.i18n.t("deleted"));
this.findAndUpdateComment(res);
}
}
@ -857,7 +855,7 @@ export class Inbox extends Component<any, InboxState> {
async handleRemoveComment(form: RemoveComment) {
const res = await HttpService.client.removeComment(form);
if (res.state == "success") {
toast(i18n.t("remove_comment"));
toast(I18NextService.i18n.t("remove_comment"));
this.findAndUpdateComment(res);
}
}
@ -892,7 +890,7 @@ export class Inbox extends Component<any, InboxState> {
async handleTransferCommunity(form: TransferCommunity) {
await HttpService.client.transferCommunity(form);
toast(i18n.t("transfer_community"));
toast(I18NextService.i18n.t("transfer_community"));
}
async handleCommentReplyRead(form: MarkCommentReplyAsRead) {
@ -1004,7 +1002,7 @@ export class Inbox extends Component<any, InboxState> {
purgeItem(purgeRes: RequestState<PurgeItemResponse>) {
if (purgeRes.state == "success") {
toast(i18n.t("purge_success"));
toast(I18NextService.i18n.t("purge_success"));
this.context.router.history.push(`/`);
}
}
@ -1013,7 +1011,7 @@ export class Inbox extends Component<any, InboxState> {
res: RequestState<PrivateMessageReportResponse | CommentReportResponse>
) {
if (res.state == "success") {
toast(i18n.t("report_created"));
toast(I18NextService.i18n.t("report_created"));
}
}

View file

@ -2,8 +2,7 @@ import { myAuth, setIsoData } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers";
import { Component, linkEvent } from "inferno";
import { GetSiteResponse, LoginResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { HttpService, UserService } from "../../services";
import { HttpService, I18NextService, UserService } from "../../services";
import { RequestState } from "../../services/HttpService";
import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon";
@ -34,7 +33,7 @@ export class PasswordChange extends Component<any, State> {
}
get documentTitle(): string {
return `${i18n.t("password_change")} - ${
return `${I18NextService.i18n.t("password_change")} - ${
this.state.siteRes.site_view.site.name
}`;
}
@ -48,7 +47,7 @@ export class PasswordChange extends Component<any, State> {
/>
<div className="row">
<div className="col-12 col-lg-6 offset-lg-3 mb-4">
<h5>{i18n.t("password_change")}</h5>
<h5>{I18NextService.i18n.t("password_change")}</h5>
{this.passwordChangeForm()}
</div>
</div>
@ -61,7 +60,7 @@ export class PasswordChange extends Component<any, State> {
<form onSubmit={linkEvent(this, this.handlePasswordChangeSubmit)}>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="new-password">
{i18n.t("new_password")}
{I18NextService.i18n.t("new_password")}
</label>
<div className="col-sm-10">
<input
@ -77,7 +76,7 @@ export class PasswordChange extends Component<any, State> {
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="verify-password">
{i18n.t("verify_password")}
{I18NextService.i18n.t("verify_password")}
</label>
<div className="col-sm-10">
<input
@ -97,7 +96,7 @@ export class PasswordChange extends Component<any, State> {
{this.state.passwordChangeRes.state == "loading" ? (
<Spinner />
) : (
capitalizeFirstLetter(i18n.t("save"))
capitalizeFirstLetter(I18NextService.i18n.t("save"))
)}
</button>
</div>

View file

@ -72,11 +72,9 @@ import {
} from "lemmy-js-client";
import moment from "moment";
import { fetchLimit, relTags } from "../../config";
import { i18n } from "../../i18next";
import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
@ -137,7 +135,7 @@ const getCommunitiesListing = (
communityViews.length > 0 && (
<div className="card border-secondary mb-3">
<div className="card-body">
<h5>{i18n.t(translationKey)}</h5>
<h5>{I18NextService.i18n.t(translationKey)}</h5>
<ul className="list-unstyled mb-0">
{communityViews.map(({ community }) => (
<li key={community.id}>
@ -422,7 +420,7 @@ export class Profile extends Component<
checked={active}
onChange={linkEvent(this, this.handleViewChange)}
/>
{i18n.t(view.toLowerCase() as NoOptionI18nKeys)}
{I18NextService.i18n.t(view.toLowerCase() as NoOptionI18nKeys)}
</label>
);
}
@ -485,22 +483,22 @@ export class Profile extends Component<
</li>
{isBanned(pv.person) && (
<li className="list-inline-item badge text-bg-danger">
{i18n.t("banned")}
{I18NextService.i18n.t("banned")}
</li>
)}
{pv.person.deleted && (
<li className="list-inline-item badge text-bg-danger">
{i18n.t("deleted")}
{I18NextService.i18n.t("deleted")}
</li>
)}
{pv.person.admin && (
<li className="list-inline-item badge text-bg-light">
{i18n.t("admin")}
{I18NextService.i18n.t("admin")}
</li>
)}
{pv.person.bot_account && (
<li className="list-inline-item badge text-bg-light">
{i18n.t("bot_account").toLowerCase()}
{I18NextService.i18n.t("bot_account").toLowerCase()}
</li>
)}
</ul>
@ -516,7 +514,7 @@ export class Profile extends Component<
rel={relTags}
href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
>
{i18n.t("send_secure_message")}
{I18NextService.i18n.t("send_secure_message")}
</a>
<Link
className={
@ -524,7 +522,7 @@ export class Profile extends Component<
}
to={`/create_private_message/${pv.person.id}`}
>
{i18n.t("send_message")}
{I18NextService.i18n.t("send_message")}
</Link>
{personBlocked ? (
<button
@ -536,7 +534,7 @@ export class Profile extends Component<
this.handleUnblockPerson
)}
>
{i18n.t("unblock_user")}
{I18NextService.i18n.t("unblock_user")}
</button>
) : (
<button
@ -548,7 +546,7 @@ export class Profile extends Component<
this.handleBlockPerson
)}
>
{i18n.t("block_user")}
{I18NextService.i18n.t("block_user")}
</button>
)}
</>
@ -563,9 +561,9 @@ export class Profile extends Component<
"d-flex align-self-start btn btn-secondary me-2"
}
onClick={linkEvent(this, this.handleModBanShow)}
aria-label={i18n.t("ban")}
aria-label={I18NextService.i18n.t("ban")}
>
{capitalizeFirstLetter(i18n.t("ban"))}
{capitalizeFirstLetter(I18NextService.i18n.t("ban"))}
</button>
) : (
<button
@ -573,9 +571,9 @@ export class Profile extends Component<
"d-flex align-self-start btn btn-secondary me-2"
}
onClick={linkEvent(this, this.handleModBanSubmit)}
aria-label={i18n.t("unban")}
aria-label={I18NextService.i18n.t("unban")}
>
{capitalizeFirstLetter(i18n.t("unban"))}
{capitalizeFirstLetter(I18NextService.i18n.t("unban"))}
</button>
))}
</div>
@ -590,13 +588,13 @@ export class Profile extends Component<
<div>
<ul className="list-inline mb-2">
<li className="list-inline-item badge text-bg-light">
{i18n.t("number_of_posts", {
{I18NextService.i18n.t("number_of_posts", {
count: Number(pv.counts.post_count),
formattedCount: numToSI(pv.counts.post_count),
})}
</li>
<li className="list-inline-item badge text-bg-light">
{i18n.t("number_of_comments", {
{I18NextService.i18n.t("number_of_comments", {
count: Number(pv.counts.comment_count),
formattedCount: numToSI(pv.counts.comment_count),
})}
@ -604,7 +602,7 @@ export class Profile extends Component<
</ul>
</div>
<div className="text-muted">
{i18n.t("joined")}{" "}
{I18NextService.i18n.t("joined")}{" "}
<MomentTime
published={pv.person.published}
showAgo
@ -614,7 +612,7 @@ export class Profile extends Component<
<div className="d-flex align-items-center text-muted mb-2">
<Icon icon="cake" />
<span className="ms-2">
{i18n.t("cake_day_title")}{" "}
{I18NextService.i18n.t("cake_day_title")}{" "}
{moment
.utc(pv.person.published)
.local()
@ -623,7 +621,7 @@ export class Profile extends Component<
</div>
{!UserService.Instance.myUserInfo && (
<div className="alert alert-info" role="alert">
{i18n.t("profile_not_logged_in_alert")}
{I18NextService.i18n.t("profile_not_logged_in_alert")}
</div>
)}
</div>
@ -641,24 +639,24 @@ export class Profile extends Component<
<form onSubmit={linkEvent(this, this.handleModBanSubmit)}>
<div className="mb-3 row col-12">
<label className="col-form-label" htmlFor="profile-ban-reason">
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id="profile-ban-reason"
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)}
/>
<label className="col-form-label" htmlFor={`mod-ban-expires`}>
{i18n.t("expires")}
{I18NextService.i18n.t("expires")}
</label>
<input
type="number"
id={`mod-ban-expires`}
className="form-control me-2"
placeholder={i18n.t("number_of_days")}
placeholder={I18NextService.i18n.t("number_of_days")}
value={this.state.banExpireDays}
onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
/>
@ -674,9 +672,9 @@ export class Profile extends Component<
<label
className="form-check-label"
htmlFor="mod-ban-remove-data"
title={i18n.t("remove_content_more")}
title={I18NextService.i18n.t("remove_content_more")}
>
{i18n.t("remove_content")}
{I18NextService.i18n.t("remove_content")}
</label>
</div>
</div>
@ -684,23 +682,23 @@ export class Profile extends Component<
{/* TODO hold off on expires until later */}
{/* <div class="mb-3 row"> */}
{/* <label class="col-form-label">Expires</label> */}
{/* <input type="date" class="form-control me-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
{/* <input type="date" class="form-control me-2" placeholder={I18NextService.i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
{/* </div> */}
<div className="mb-3 row">
<button
type="reset"
className="btn btn-secondary me-2"
aria-label={i18n.t("cancel")}
aria-label={I18NextService.i18n.t("cancel")}
onClick={linkEvent(this, this.handleModBanSubmitCancel)}
>
{i18n.t("cancel")}
{I18NextService.i18n.t("cancel")}
</button>
<button
type="submit"
className="btn btn-secondary"
aria-label={i18n.t("ban")}
aria-label={I18NextService.i18n.t("ban")}
>
{i18n.t("ban")} {pv.person.name}
{I18NextService.i18n.t("ban")} {pv.person.name}
</button>
</div>
</form>
@ -904,14 +902,14 @@ export class Profile extends Component<
async handleCommentReport(form: CreateCommentReport) {
const reportRes = await HttpService.client.createCommentReport(form);
if (reportRes.state === "success") {
toast(i18n.t("report_created"));
toast(I18NextService.i18n.t("report_created"));
}
}
async handlePostReport(form: CreatePostReport) {
const reportRes = await HttpService.client.createPostReport(form);
if (reportRes.state === "success") {
toast(i18n.t("report_created"));
toast(I18NextService.i18n.t("report_created"));
}
}
@ -935,7 +933,7 @@ export class Profile extends Component<
async handleTransferCommunity(form: TransferCommunity) {
await HttpService.client.transferCommunity(form);
toast(i18n.t("transfer_community"));
toast(I18NextService.i18n.t("transfer_community"));
}
async handleCommentReplyRead(form: MarkCommentReplyAsRead) {
@ -999,7 +997,7 @@ export class Profile extends Component<
purgeItem(purgeRes: RequestState<PurgeItemResponse>) {
if (purgeRes.state == "success") {
toast(i18n.t("purge_success"));
toast(I18NextService.i18n.t("purge_success"));
this.context.router.history.push(`/`);
}
}

View file

@ -12,10 +12,8 @@ import {
RegistrationApplicationView,
} from "lemmy-js-client";
import { fetchLimit } from "../../config";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { setupTippy } from "../../tippy";
import { HtmlTags } from "../common/html-tags";
@ -79,7 +77,7 @@ export class RegistrationApplications extends Component<
get documentTitle(): string {
const mui = UserService.Instance.myUserInfo;
return mui
? `@${mui.local_user_view.person.name} ${i18n.t(
? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
"registration_applications"
)} - ${this.state.siteRes.site_view.site.name}`
: "";
@ -102,7 +100,9 @@ export class RegistrationApplications extends Component<
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<h5 className="mb-2">{i18n.t("registration_applications")}</h5>
<h5 className="mb-2">
{I18NextService.i18n.t("registration_applications")}
</h5>
{this.selects()}
{this.applicationList(apps)}
<Paginator
@ -139,7 +139,7 @@ export class RegistrationApplications extends Component<
checked={this.state.unreadOrAll == UnreadOrAll.Unread}
onChange={linkEvent(this, this.handleUnreadOrAllChange)}
/>
{i18n.t("unread")}
{I18NextService.i18n.t("unread")}
</label>
<label
className={`btn btn-outline-secondary pointer
@ -153,7 +153,7 @@ export class RegistrationApplications extends Component<
checked={this.state.unreadOrAll == UnreadOrAll.All}
onChange={linkEvent(this, this.handleUnreadOrAllChange)}
/>
{i18n.t("all")}
{I18NextService.i18n.t("all")}
</label>
</div>
);

View file

@ -27,10 +27,13 @@ import {
ResolvePrivateMessageReport,
} from "lemmy-js-client";
import { fetchLimit } from "../../config";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { HttpService, UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import {
FirstLoadService,
HttpService,
I18NextService,
UserService,
} from "../../services";
import { RequestState } from "../../services/HttpService";
import { CommentReport } from "../comment/comment-report";
import { HtmlTags } from "../common/html-tags";
@ -134,9 +137,9 @@ export class Reports extends Component<any, ReportsState> {
get documentTitle(): string {
const mui = UserService.Instance.myUserInfo;
return mui
? `@${mui.local_user_view.person.name} ${i18n.t("reports")} - ${
this.state.siteRes.site_view.site.name
}`
? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
"reports"
)} - ${this.state.siteRes.site_view.site.name}`
: "";
}
@ -149,7 +152,7 @@ export class Reports extends Component<any, ReportsState> {
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<h5 className="mb-2">{i18n.t("reports")}</h5>
<h5 className="mb-2">{I18NextService.i18n.t("reports")}</h5>
{this.selects()}
{this.section}
<Paginator
@ -198,7 +201,7 @@ export class Reports extends Component<any, ReportsState> {
checked={this.state.unreadOrAll == UnreadOrAll.Unread}
onChange={linkEvent(this, this.handleUnreadOrAllChange)}
/>
{i18n.t("unread")}
{I18NextService.i18n.t("unread")}
</label>
<label
className={`btn btn-outline-secondary pointer
@ -212,7 +215,7 @@ export class Reports extends Component<any, ReportsState> {
checked={this.state.unreadOrAll == UnreadOrAll.All}
onChange={linkEvent(this, this.handleUnreadOrAllChange)}
/>
{i18n.t("all")}
{I18NextService.i18n.t("all")}
</label>
</div>
);
@ -233,7 +236,7 @@ export class Reports extends Component<any, ReportsState> {
checked={this.state.messageType == MessageType.All}
onChange={linkEvent(this, this.handleMessageTypeChange)}
/>
{i18n.t("all")}
{I18NextService.i18n.t("all")}
</label>
<label
className={`btn btn-outline-secondary pointer
@ -247,7 +250,7 @@ export class Reports extends Component<any, ReportsState> {
checked={this.state.messageType == MessageType.CommentReport}
onChange={linkEvent(this, this.handleMessageTypeChange)}
/>
{i18n.t("comments")}
{I18NextService.i18n.t("comments")}
</label>
<label
className={`btn btn-outline-secondary pointer
@ -261,7 +264,7 @@ export class Reports extends Component<any, ReportsState> {
checked={this.state.messageType == MessageType.PostReport}
onChange={linkEvent(this, this.handleMessageTypeChange)}
/>
{i18n.t("posts")}
{I18NextService.i18n.t("posts")}
</label>
{amAdmin() && (
<label
@ -281,7 +284,7 @@ export class Reports extends Component<any, ReportsState> {
}
onChange={linkEvent(this, this.handleMessageTypeChange)}
/>
{i18n.t("messages")}
{I18NextService.i18n.t("messages")}
</label>
)}
</div>

View file

@ -29,9 +29,9 @@ import {
SortType,
} from "lemmy-js-client";
import { elementUrl, emDash, relTags } from "../../config";
import { i18n, languages } from "../../i18next";
import { UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { I18NextService, languages } from "../../services/I18NextService";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
@ -113,7 +113,7 @@ const Filter = ({
className="col-md-4 col-form-label"
htmlFor={`block-${filterType}-filter`}
>
{i18n.t(`block_${filterType}` as NoOptionI18nKeys)}
{I18NextService.i18n.t(`block_${filterType}` as NoOptionI18nKeys)}
</label>
<div className="col-md-8">
<SearchableSelect
@ -233,7 +233,7 @@ export class Settings extends Component<any, SettingsState> {
}
get documentTitle(): string {
return i18n.t("settings");
return I18NextService.i18n.t("settings");
}
render() {
@ -249,12 +249,12 @@ export class Settings extends Component<any, SettingsState> {
tabs={[
{
key: "settings",
label: i18n.t("settings"),
label: I18NextService.i18n.t("settings"),
getNode: this.userSettings,
},
{
key: "blocks",
label: i18n.t("blocks"),
label: I18NextService.i18n.t("blocks"),
getNode: this.blockCards,
},
]}
@ -316,11 +316,11 @@ export class Settings extends Component<any, SettingsState> {
changePasswordHtmlForm() {
return (
<>
<h5>{i18n.t("change_password")}</h5>
<h5>{I18NextService.i18n.t("change_password")}</h5>
<form onSubmit={linkEvent(this, this.handleChangePasswordSubmit)}>
<div className="mb-3 row">
<label className="col-sm-5 col-form-label" htmlFor="user-password">
{i18n.t("new_password")}
{I18NextService.i18n.t("new_password")}
</label>
<div className="col-sm-7">
<input
@ -339,7 +339,7 @@ export class Settings extends Component<any, SettingsState> {
className="col-sm-5 col-form-label"
htmlFor="user-verify-password"
>
{i18n.t("verify_password")}
{I18NextService.i18n.t("verify_password")}
</label>
<div className="col-sm-7">
<input
@ -358,7 +358,7 @@ export class Settings extends Component<any, SettingsState> {
className="col-sm-5 col-form-label"
htmlFor="user-old-password"
>
{i18n.t("old_password")}
{I18NextService.i18n.t("old_password")}
</label>
<div className="col-sm-7">
<input
@ -380,7 +380,7 @@ export class Settings extends Component<any, SettingsState> {
{this.state.changePasswordRes.state === "loading" ? (
<Spinner />
) : (
capitalizeFirstLetter(i18n.t("save"))
capitalizeFirstLetter(I18NextService.i18n.t("save"))
)}
</button>
</div>
@ -409,7 +409,7 @@ export class Settings extends Component<any, SettingsState> {
blockedUsersList() {
return (
<>
<h5>{i18n.t("blocked_users")}</h5>
<h5>{I18NextService.i18n.t("blocked_users")}</h5>
<ul className="list-unstyled mb-0">
{this.state.personBlocks.map(pb => (
<li key={pb.target.id}>
@ -421,7 +421,7 @@ export class Settings extends Component<any, SettingsState> {
{ ctx: this, recipientId: pb.target.id },
this.handleUnblockPerson
)}
data-tippy-content={i18n.t("unblock_user")}
data-tippy-content={I18NextService.i18n.t("unblock_user")}
>
<Icon icon="x" classes="icon-inline" />
</button>
@ -453,7 +453,7 @@ export class Settings extends Component<any, SettingsState> {
blockedCommunitiesList() {
return (
<>
<h5>{i18n.t("blocked_communities")}</h5>
<h5>{I18NextService.i18n.t("blocked_communities")}</h5>
<ul className="list-unstyled mb-0">
{this.state.communityBlocks.map(cb => (
<li key={cb.community.id}>
@ -465,7 +465,9 @@ export class Settings extends Component<any, SettingsState> {
{ ctx: this, communityId: cb.community.id },
this.handleUnblockCommunity
)}
data-tippy-content={i18n.t("unblock_community")}
data-tippy-content={I18NextService.i18n.t(
"unblock_community"
)}
>
<Icon icon="x" classes="icon-inline" />
</button>
@ -482,18 +484,18 @@ export class Settings extends Component<any, SettingsState> {
return (
<>
<h5>{i18n.t("settings")}</h5>
<h5>{I18NextService.i18n.t("settings")}</h5>
<form onSubmit={linkEvent(this, this.handleSaveSettingsSubmit)}>
<div className="mb-3 row">
<label className="col-sm-3 col-form-label" htmlFor="display-name">
{i18n.t("display_name")}
{I18NextService.i18n.t("display_name")}
</label>
<div className="col-sm-9">
<input
id="display-name"
type="text"
className="form-control"
placeholder={i18n.t("optional")}
placeholder={I18NextService.i18n.t("optional")}
value={this.state.saveUserSettingsForm.display_name}
onInput={linkEvent(this, this.handleDisplayNameChange)}
pattern="^(?!@)(.+)$"
@ -503,7 +505,7 @@ export class Settings extends Component<any, SettingsState> {
</div>
<div className="mb-3 row">
<label className="col-sm-3 col-form-label" htmlFor="user-bio">
{i18n.t("bio")}
{I18NextService.i18n.t("bio")}
</label>
<div className="col-sm-9">
<MarkdownTextArea
@ -518,14 +520,14 @@ export class Settings extends Component<any, SettingsState> {
</div>
<div className="mb-3 row">
<label className="col-sm-3 col-form-label" htmlFor="user-email">
{i18n.t("email")}
{I18NextService.i18n.t("email")}
</label>
<div className="col-sm-9">
<input
type="email"
id="user-email"
className="form-control"
placeholder={i18n.t("optional")}
placeholder={I18NextService.i18n.t("optional")}
value={this.state.saveUserSettingsForm.email}
onInput={linkEvent(this, this.handleEmailChange)}
minLength={3}
@ -535,7 +537,7 @@ export class Settings extends Component<any, SettingsState> {
<div className="mb-3 row">
<label className="col-sm-3 col-form-label" htmlFor="matrix-user-id">
<a href={elementUrl} rel={relTags}>
{i18n.t("matrix_user_id")}
{I18NextService.i18n.t("matrix_user_id")}
</a>
</label>
<div className="col-sm-9">
@ -552,11 +554,11 @@ export class Settings extends Component<any, SettingsState> {
</div>
<div className="mb-3 row">
<label className="col-sm-3 col-form-label">
{i18n.t("avatar")}
{I18NextService.i18n.t("avatar")}
</label>
<div className="col-sm-9">
<ImageUploadForm
uploadTitle={i18n.t("upload_avatar")}
uploadTitle={I18NextService.i18n.t("upload_avatar")}
imageSrc={this.state.saveUserSettingsForm.avatar}
onUpload={this.handleAvatarUpload}
onRemove={this.handleAvatarRemove}
@ -566,11 +568,11 @@ export class Settings extends Component<any, SettingsState> {
</div>
<div className="mb-3 row">
<label className="col-sm-3 col-form-label">
{i18n.t("banner")}
{I18NextService.i18n.t("banner")}
</label>
<div className="col-sm-9">
<ImageUploadForm
uploadTitle={i18n.t("upload_banner")}
uploadTitle={I18NextService.i18n.t("upload_banner")}
imageSrc={this.state.saveUserSettingsForm.banner}
onUpload={this.handleBannerUpload}
onRemove={this.handleBannerRemove}
@ -579,7 +581,7 @@ export class Settings extends Component<any, SettingsState> {
</div>
<div className="mb-3 row">
<label className="col-sm-3 form-label" htmlFor="user-language">
{i18n.t("interface_language")}
{I18NextService.i18n.t("interface_language")}
</label>
<div className="col-sm-9">
<select
@ -589,9 +591,11 @@ export class Settings extends Component<any, SettingsState> {
className="form-select d-inline-block w-auto"
>
<option disabled aria-hidden="true">
{i18n.t("interface_language")}
{I18NextService.i18n.t("interface_language")}
</option>
<option value="browser">
{I18NextService.i18n.t("browser_default")}
</option>
<option value="browser">{i18n.t("browser_default")}</option>
<option disabled aria-hidden="true">
</option>
@ -616,7 +620,7 @@ export class Settings extends Component<any, SettingsState> {
/>
<div className="mb-3 row">
<label className="col-sm-3 col-form-label" htmlFor="user-theme">
{i18n.t("theme")}
{I18NextService.i18n.t("theme")}
</label>
<div className="col-sm-9">
<select
@ -626,9 +630,11 @@ export class Settings extends Component<any, SettingsState> {
className="form-select d-inline-block w-auto"
>
<option disabled aria-hidden="true">
{i18n.t("theme")}
{I18NextService.i18n.t("theme")}
</option>
<option value="browser">
{I18NextService.i18n.t("browser_default")}
</option>
<option value="browser">{i18n.t("browser_default")}</option>
{this.state.themeList.map(theme => (
<option key={theme} value={theme}>
{theme}
@ -638,7 +644,9 @@ export class Settings extends Component<any, SettingsState> {
</div>
</div>
<form className="mb-3 row">
<label className="col-sm-3 col-form-label">{i18n.t("type")}</label>
<label className="col-sm-3 col-form-label">
{I18NextService.i18n.t("type")}
</label>
<div className="col-sm-9">
<ListingTypeSelect
type_={
@ -653,7 +661,7 @@ export class Settings extends Component<any, SettingsState> {
</form>
<form className="mb-3 row">
<label className="col-sm-3 col-form-label">
{i18n.t("sort_type")}
{I18NextService.i18n.t("sort_type")}
</label>
<div className="col-sm-9">
<SortSelect
@ -674,7 +682,7 @@ export class Settings extends Component<any, SettingsState> {
onChange={linkEvent(this, this.handleShowNsfwChange)}
/>
<label className="form-check-label" htmlFor="user-show-nsfw">
{i18n.t("show_nsfw")}
{I18NextService.i18n.t("show_nsfw")}
</label>
</div>
</div>
@ -688,7 +696,7 @@ export class Settings extends Component<any, SettingsState> {
onChange={linkEvent(this, this.handleShowScoresChange)}
/>
<label className="form-check-label" htmlFor="user-show-scores">
{i18n.t("show_scores")}
{I18NextService.i18n.t("show_scores")}
</label>
</div>
</div>
@ -702,7 +710,7 @@ export class Settings extends Component<any, SettingsState> {
onChange={linkEvent(this, this.handleShowAvatarsChange)}
/>
<label className="form-check-label" htmlFor="user-show-avatars">
{i18n.t("show_avatars")}
{I18NextService.i18n.t("show_avatars")}
</label>
</div>
</div>
@ -716,7 +724,7 @@ export class Settings extends Component<any, SettingsState> {
onChange={linkEvent(this, this.handleBotAccount)}
/>
<label className="form-check-label" htmlFor="user-bot-account">
{i18n.t("bot_account")}
{I18NextService.i18n.t("bot_account")}
</label>
</div>
</div>
@ -733,7 +741,7 @@ export class Settings extends Component<any, SettingsState> {
className="form-check-label"
htmlFor="user-show-bot-accounts"
>
{i18n.t("show_bot_accounts")}
{I18NextService.i18n.t("show_bot_accounts")}
</label>
</div>
</div>
@ -750,7 +758,7 @@ export class Settings extends Component<any, SettingsState> {
className="form-check-label"
htmlFor="user-show-read-posts"
>
{i18n.t("show_read_posts")}
{I18NextService.i18n.t("show_read_posts")}
</label>
</div>
</div>
@ -767,7 +775,7 @@ export class Settings extends Component<any, SettingsState> {
className="form-check-label"
htmlFor="user-show-new-post-notifs"
>
{i18n.t("show_new_post_notifs")}
{I18NextService.i18n.t("show_new_post_notifs")}
</label>
</div>
</div>
@ -790,7 +798,7 @@ export class Settings extends Component<any, SettingsState> {
className="form-check-label"
htmlFor="user-send-notifications-to-email"
>
{i18n.t("send_notifications_to_email")}
{I18NextService.i18n.t("send_notifications_to_email")}
</label>
</div>
</div>
@ -800,7 +808,7 @@ export class Settings extends Component<any, SettingsState> {
{this.state.saveRes.state === "loading" ? (
<Spinner />
) : (
capitalizeFirstLetter(i18n.t("save"))
capitalizeFirstLetter(I18NextService.i18n.t("save"))
)}
</button>
</div>
@ -813,12 +821,12 @@ export class Settings extends Component<any, SettingsState> {
this.handleDeleteAccountShowConfirmToggle
)}
>
{i18n.t("delete_account")}
{I18NextService.i18n.t("delete_account")}
</button>
{this.state.deleteAccountShowConfirm && (
<>
<div className="my-2 alert alert-danger" role="alert">
{i18n.t("delete_account_confirm")}
{I18NextService.i18n.t("delete_account_confirm")}
</div>
<input
type="password"
@ -839,7 +847,7 @@ export class Settings extends Component<any, SettingsState> {
{this.state.deleteAccountRes.state === "loading" ? (
<Spinner />
) : (
capitalizeFirstLetter(i18n.t("delete"))
capitalizeFirstLetter(I18NextService.i18n.t("delete"))
)}
</button>
<button
@ -849,7 +857,7 @@ export class Settings extends Component<any, SettingsState> {
this.handleDeleteAccountShowConfirmToggle
)}
>
{i18n.t("cancel")}
{I18NextService.i18n.t("cancel")}
</button>
</>
)}
@ -876,7 +884,7 @@ export class Settings extends Component<any, SettingsState> {
onChange={linkEvent(this, this.handleGenerateTotp)}
/>
<label className="form-check-label" htmlFor="user-generate-totp">
{i18n.t("set_up_two_factor")}
{I18NextService.i18n.t("set_up_two_factor")}
</label>
</div>
</div>
@ -886,7 +894,7 @@ export class Settings extends Component<any, SettingsState> {
<>
<div>
<a className="btn btn-secondary mb-2" href={totpUrl}>
{i18n.t("two_factor_link")}
{I18NextService.i18n.t("two_factor_link")}
</a>
</div>
<div className="input-group mb-3">
@ -901,7 +909,7 @@ export class Settings extends Component<any, SettingsState> {
onChange={linkEvent(this, this.handleRemoveTotp)}
/>
<label className="form-check-label" htmlFor="user-remove-totp">
{i18n.t("remove_two_factor")}
{I18NextService.i18n.t("remove_two_factor")}
</label>
</div>
</div>
@ -1050,7 +1058,7 @@ export class Settings extends Component<any, SettingsState> {
// Coerce false to undefined here, so it won't generate it.
const checked: boolean | undefined = event.target.checked || undefined;
if (checked) {
toast(i18n.t("two_factor_setup_instructions"));
toast(I18NextService.i18n.t("two_factor_setup_instructions"));
}
i.setState(s => ((s.saveUserSettingsForm.generate_totp_2fa = checked), s));
}
@ -1078,7 +1086,9 @@ export class Settings extends Component<any, SettingsState> {
handleInterfaceLangChange(i: Settings, event: any) {
const newLang = event.target.value ?? "browser";
i18n.changeLanguage(newLang === "browser" ? navigator.languages : newLang);
I18NextService.i18n.changeLanguage(
newLang === "browser" ? navigator.languages : newLang
);
i.setState(
s => ((s.saveUserSettingsForm.interface_language = event.target.value), s)
@ -1168,7 +1178,7 @@ export class Settings extends Component<any, SettingsState> {
if (saveRes.state === "success") {
UserService.Instance.login(saveRes.data);
location.reload();
toast(i18n.t("saved"));
toast(I18NextService.i18n.t("saved"));
window.scrollTo(0, 0);
}
@ -1191,7 +1201,7 @@ export class Settings extends Component<any, SettingsState> {
if (changePasswordRes.state === "success") {
UserService.Instance.login(changePasswordRes.data);
window.scrollTo(0, 0);
toast(i18n.t("password_changed"));
toast(I18NextService.i18n.t("password_changed"));
}
i.setState({ changePasswordRes });

View file

@ -1,7 +1,7 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno";
import { GetSiteResponse, VerifyEmailResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
@ -36,7 +36,7 @@ export class VerifyEmail extends Component<any, State> {
});
if (this.state.verifyRes.state == "success") {
toast(i18n.t("email_verified"));
toast(I18NextService.i18n.t("email_verified"));
this.props.history.push("/login");
}
}
@ -46,7 +46,7 @@ export class VerifyEmail extends Component<any, State> {
}
get documentTitle(): string {
return `${i18n.t("verify_email")} - ${
return `${I18NextService.i18n.t("verify_email")} - ${
this.state.siteRes.site_view.site.name
}`;
}
@ -60,7 +60,7 @@ export class VerifyEmail extends Component<any, State> {
/>
<div className="row">
<div className="col-12 col-lg-6 offset-lg-3 mb-4">
<h5>{i18n.t("verify_email")}</h5>
<h5>{I18NextService.i18n.t("verify_email")}</h5>
{this.state.verifyRes.state == "loading" && (
<h5>
<Spinner large />

View file

@ -11,9 +11,8 @@ import {
GetSiteResponse,
ListCommunitiesResponse,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { InitialFetchRequest, PostFormParams } from "../../interfaces";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService } from "../../services";
import {
HttpService,
RequestState,
@ -143,7 +142,7 @@ export class CreatePost extends Component<
}
get documentTitle(): string {
return `${i18n.t("create_post")} - ${
return `${I18NextService.i18n.t("create_post")} - ${
this.state.siteRes.site_view.site.name
}`;
}
@ -171,7 +170,7 @@ export class CreatePost extends Component<
id="createPostForm"
className="col-12 col-lg-6 offset-lg-3 mb-4"
>
<h1 className="h4">{i18n.t("create_post")}</h1>
<h1 className="h4">{I18NextService.i18n.t("create_post")}</h1>
<PostForm
onCreate={this.handlePostCreate}
params={locationState}

View file

@ -2,7 +2,7 @@ import { Component, linkEvent } from "inferno";
import { Post } from "lemmy-js-client";
import * as sanitizeHtml from "sanitize-html";
import { relTags } from "../../config";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Icon } from "../common/icon";
interface MetadataCardProps {
@ -66,7 +66,7 @@ export class MetadataCard extends Component<
className="mt-2 btn btn-secondary text-monospace"
onClick={linkEvent(this, this.handleIframeExpand)}
>
{i18n.t("expand_here")}
{I18NextService.i18n.t("expand_here")}
</button>
)}
</div>

View file

@ -31,9 +31,8 @@ import {
trendingFetchLimit,
webArchiveUrl,
} from "../../config";
import { i18n } from "../../i18next";
import { PostFormParams } from "../../interfaces";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
@ -342,7 +341,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
/>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="post-url">
{i18n.t("url")}
{I18NextService.i18n.t("url")}
</label>
<div className="col-sm-10">
<input
@ -360,7 +359,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
className={`${
UserService.Instance.myUserInfo && "pointer"
} d-inline-block float-right text-muted font-weight-bold`}
data-tippy-content={i18n.t("upload_image")}
data-tippy-content={I18NextService.i18n.t("upload_image")}
>
<Icon icon="image" classes="icon-inline" />
</label>
@ -381,7 +380,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
className="me-2 d-inline-block float-right text-muted small font-weight-bold"
rel={relTags}
>
archive.org {i18n.t("archive_link")}
archive.org {I18NextService.i18n.t("archive_link")}
</a>
<a
href={`${ghostArchiveUrl}/search?term=${encodeURIComponent(
@ -390,7 +389,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
className="me-2 d-inline-block float-right text-muted small font-weight-bold"
rel={relTags}
>
ghostarchive.org {i18n.t("archive_link")}
ghostarchive.org {I18NextService.i18n.t("archive_link")}
</a>
<a
href={`${archiveTodayUrl}/?run=1&url=${encodeURIComponent(
@ -399,7 +398,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
className="me-2 d-inline-block float-right text-muted small font-weight-bold"
rel={relTags}
>
archive.today {i18n.t("archive_link")}
archive.today {I18NextService.i18n.t("archive_link")}
</a>
</div>
)}
@ -411,17 +410,17 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
<button
className="btn btn-danger btn-sm mt-2"
onClick={linkEvent(this, handleImageDelete)}
aria-label={i18n.t("delete")}
data-tippy-content={i18n.t("delete")}
aria-label={I18NextService.i18n.t("delete")}
data-tippy-content={I18NextService.i18n.t("delete")}
>
<Icon icon="x" classes="icon-inline me-1" />
{capitalizeFirstLetter(i18n.t("delete"))}
{capitalizeFirstLetter(I18NextService.i18n.t("delete"))}
</button>
)}
{this.props.crossPosts && this.props.crossPosts.length > 0 && (
<>
<div className="my-1 text-muted small font-weight-bold">
{i18n.t("cross_posts")}
{I18NextService.i18n.t("cross_posts")}
</div>
<PostListings
showCommunity
@ -455,7 +454,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="post-title">
{i18n.t("title")}
{I18NextService.i18n.t("title")}
</label>
<div className="col-sm-10">
<textarea
@ -472,7 +471,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
/>
{!validTitle(this.state.form.name) && (
<div className="invalid-feedback">
{i18n.t("invalid_post_title")}
{I18NextService.i18n.t("invalid_post_title")}
</div>
)}
{this.renderSuggestedPosts()}
@ -480,7 +479,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
</div>
<div className="mb-3 row">
<label className="col-sm-2 col-form-label">{i18n.t("body")}</label>
<label className="col-sm-2 col-form-label">
{I18NextService.i18n.t("body")}
</label>
<div className="col-sm-10">
<MarkdownTextArea
initialContent={this.state.form.body}
@ -501,7 +502,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
{!this.props.post_view && (
<div className="mb-3 row">
<label className="col-sm-2 col-form-label" htmlFor="post-community">
{i18n.t("community")}
{I18NextService.i18n.t("community")}
</label>
<div className="col-sm-10">
<SearchableSelect
@ -509,7 +510,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
value={this.state.form.community_id}
options={[
{
label: i18n.t("select_a_community"),
label: I18NextService.i18n.t("select_a_community"),
value: "",
disabled: true,
} as Choice,
@ -530,7 +531,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
checked={this.state.form.nsfw}
onChange={linkEvent(this, handlePostNsfwChange)}
/>
<label className="form-check-label">{i18n.t("nsfw")}</label>
<label className="form-check-label">
{I18NextService.i18n.t("nsfw")}
</label>
</div>
)}
<input
@ -553,9 +556,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
{this.state.loading ? (
<Spinner />
) : this.props.post_view ? (
capitalizeFirstLetter(i18n.t("save"))
capitalizeFirstLetter(I18NextService.i18n.t("save"))
) : (
capitalizeFirstLetter(i18n.t("create"))
capitalizeFirstLetter(I18NextService.i18n.t("create"))
)}
</button>
{this.props.post_view && (
@ -564,7 +567,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
className="btn btn-secondary"
onClick={linkEvent(this, handleCancel)}
>
{i18n.t("cancel")}
{I18NextService.i18n.t("cancel")}
</button>
)}
</div>
@ -590,7 +593,8 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
copySuggestedTitle
)}
>
{i18n.t("copy_suggested_title", { title: "" })} {suggestedTitle}
{I18NextService.i18n.t("copy_suggested_title", { title: "" })}{" "}
{suggestedTitle}
</div>
)
);
@ -610,7 +614,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
suggestedPosts.length > 0 && (
<>
<div className="my-1 text-muted small font-weight-bold">
{i18n.t("related_posts")}
{I18NextService.i18n.t("related_posts")}
</div>
<PostListings
showCommunity

View file

@ -39,10 +39,9 @@ import {
} from "lemmy-js-client";
import { relTags } from "../../config";
import { getExternalHost, getHttpBase } from "../../env";
import { i18n } from "../../i18next";
import { BanType, PostFormParams, PurgeType, VoteType } from "../../interfaces";
import { mdNoImages, mdToHtml, mdToHtmlInline } from "../../markdown";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { setupTippy } from "../../tippy";
import { Icon, PurgeWarning, Spinner } from "../common/icon";
import { MomentTime } from "../common/moment-time";
@ -298,9 +297,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<a
href={this.imageSrc}
className="text-body d-inline-block position-relative mb-2"
data-tippy-content={i18n.t("expand_here")}
data-tippy-content={I18NextService.i18n.t("expand_here")}
onClick={linkEvent(this, this.handleImageExpandClick)}
aria-label={i18n.t("expand_here")}
aria-label={I18NextService.i18n.t("expand_here")}
>
{this.imgThumb(this.imageSrc)}
<Icon icon="image" classes="mini-overlay" />
@ -347,7 +346,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<Link
className="text-body"
to={`/post/${post.id}`}
title={i18n.t("comments")}
title={I18NextService.i18n.t("comments")}
>
<div className="thumbnail rounded bg-light d-flex justify-content-center">
<Icon icon="message-square" classes="d-flex align-items-center" />
@ -365,20 +364,25 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<PersonListing person={post_view.creator} />
{this.creatorIsMod_ && (
<span className="mx-1 badge text-bg-light">{i18n.t("mod")}</span>
<span className="mx-1 badge text-bg-light">
{I18NextService.i18n.t("mod")}
</span>
)}
{this.creatorIsAdmin_ && (
<span className="mx-1 badge text-bg-light">{i18n.t("admin")}</span>
<span className="mx-1 badge text-bg-light">
{I18NextService.i18n.t("admin")}
</span>
)}
{post_view.creator.bot_account && (
<span className="mx-1 badge text-bg-light">
{i18n.t("bot_account").toLowerCase()}
{I18NextService.i18n.t("bot_account").toLowerCase()}
</span>
)}
{this.props.showCommunity && (
<>
{" "}
{i18n.t("to")} <CommunityLink community={post_view.community} />
{I18NextService.i18n.t("to")}{" "}
<CommunityLink community={post_view.community} />
</>
)}
</li>
@ -412,8 +416,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this.postView.my_vote == 1 ? "text-info" : "text-muted"
}`}
onClick={linkEvent(this, this.handleUpvote)}
data-tippy-content={i18n.t("upvote")}
aria-label={i18n.t("upvote")}
data-tippy-content={I18NextService.i18n.t("upvote")}
aria-label={I18NextService.i18n.t("upvote")}
aria-pressed={this.postView.my_vote === 1}
>
{this.state.upvoteLoading ? (
@ -438,8 +442,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this.postView.my_vote == -1 ? "text-danger" : "text-muted"
}`}
onClick={linkEvent(this, this.handleDownvote)}
data-tippy-content={i18n.t("downvote")}
aria-label={i18n.t("downvote")}
data-tippy-content={I18NextService.i18n.t("downvote")}
aria-label={I18NextService.i18n.t("downvote")}
aria-pressed={this.postView.my_vote === -1}
>
{this.state.downvoteLoading ? (
@ -463,7 +467,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
: "text-primary"
}`}
to={`/post/${post.id}`}
title={i18n.t("comments")}
title={I18NextService.i18n.t("comments")}
>
<span
className="d-inline"
@ -501,7 +505,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
(post.thumbnail_url && (
<button
className="btn btn-sm text-monospace text-muted d-inline-block"
data-tippy-content={i18n.t("expand_here")}
data-tippy-content={I18NextService.i18n.t("expand_here")}
onClick={linkEvent(this, this.handleImageExpandClick)}
>
<Icon
@ -514,13 +518,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
))}
{post.removed && (
<small className="ms-2 badge text-bg-secondary">
{i18n.t("removed")}
{I18NextService.i18n.t("removed")}
</small>
)}
{post.deleted && (
<small
className="unselectable pointer ms-2 text-muted font-italic"
data-tippy-content={i18n.t("deleted")}
data-tippy-content={I18NextService.i18n.t("deleted")}
>
<Icon icon="trash" classes="icon-inline text-danger" />
</small>
@ -528,7 +532,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{post.locked && (
<small
className="unselectable pointer ms-2 text-muted font-italic"
data-tippy-content={i18n.t("locked")}
data-tippy-content={I18NextService.i18n.t("locked")}
>
<Icon icon="lock" classes="icon-inline text-danger" />
</small>
@ -536,8 +540,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{post.featured_community && (
<small
className="unselectable pointer ms-2 text-muted font-italic"
data-tippy-content={i18n.t("featured_in_community")}
aria-label={i18n.t("featured_in_community")}
data-tippy-content={I18NextService.i18n.t(
"featured_in_community"
)}
aria-label={I18NextService.i18n.t("featured_in_community")}
>
<Icon icon="pin" classes="icon-inline text-primary" />
</small>
@ -545,15 +551,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{post.featured_local && (
<small
className="unselectable pointer ms-2 text-muted font-italic"
data-tippy-content={i18n.t("featured_in_local")}
aria-label={i18n.t("featured_in_local")}
data-tippy-content={I18NextService.i18n.t("featured_in_local")}
aria-label={I18NextService.i18n.t("featured_in_local")}
>
<Icon icon="pin" classes="icon-inline text-secondary" />
</small>
)}
{post.nsfw && (
<small className="ms-2 badge text-bg-danger">
{i18n.t("nsfw")}
{I18NextService.i18n.t("nsfw")}
</small>
)}
</div>
@ -587,7 +593,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
return dupes && dupes.length > 0 ? (
<ul className="list-inline mb-1 small text-muted">
<>
<li className="list-inline-item me-2">{i18n.t("cross_posted_to")}</li>
<li className="list-inline-item me-2">
{I18NextService.i18n.t("cross_posted_to")}
</li>
{dupes.map(pv => (
<li key={pv.post.id} className="list-inline-item me-2">
<Link to={`/post/${pv.post.id}`}>
@ -622,7 +630,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{!post.local && (
<a
className="btn btn-sm btn-animate text-muted py-0"
title={i18n.t("link")}
title={I18NextService.i18n.t("link")}
href={post.ap_id}
>
<Icon icon="fedilink" inline />
@ -681,11 +689,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button
className="btn btn-sm btn-animate text-muted py-0 dropdown-toggle"
onClick={linkEvent(this, this.handleShowAdvanced)}
data-tippy-content={i18n.t("more")}
data-tippy-content={I18NextService.i18n.t("more")}
data-bs-toggle="dropdown"
aria-expanded="false"
aria-controls="advancedButtonsDropdown"
aria-label={i18n.t("more")}
aria-label={I18NextService.i18n.t("more")}
>
<Icon icon="more-vertical" inline />
</button>
@ -725,7 +733,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
get commentsButton() {
const post_view = this.postView;
const title = i18n.t("number_of_comments", {
const title = I18NextService.i18n.t("number_of_comments", {
count: Number(post_view.counts.comments),
formattedCount: Number(post_view.counts.comments),
});
@ -743,7 +751,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</span>
{this.unreadCount && (
<span className="text-muted fst-italic">
({this.unreadCount} {i18n.t("new")})
({this.unreadCount} {I18NextService.i18n.t("new")})
</span>
)}
</Link>
@ -771,7 +779,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
}`}
{...tippy}
onClick={linkEvent(this, this.handleUpvote)}
aria-label={i18n.t("upvote")}
aria-label={I18NextService.i18n.t("upvote")}
aria-pressed={this.postView.my_vote === 1}
>
{this.state.upvoteLoading ? (
@ -794,7 +802,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
}`}
onClick={linkEvent(this, this.handleDownvote)}
{...tippy}
aria-label={i18n.t("downvote")}
aria-label={I18NextService.i18n.t("downvote")}
aria-pressed={this.postView.my_vote === -1}
>
{this.state.downvoteLoading ? (
@ -822,7 +830,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
get saveButton() {
const saved = this.postView.saved;
const label = saved ? i18n.t("unsave") : i18n.t("save");
const label = saved
? I18NextService.i18n.t("unsave")
: I18NextService.i18n.t("save");
return (
<button
className="btn btn-sm btn-animate text-muted py-0"
@ -855,9 +865,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
key: "",
search: "",
}}
title={i18n.t("cross_post")}
data-tippy-content={i18n.t("cross_post")}
aria-label={i18n.t("cross_post")}
title={I18NextService.i18n.t("cross_post")}
data-tippy-content={I18NextService.i18n.t("cross_post")}
aria-label={I18NextService.i18n.t("cross_post")}
>
<Icon icon="copy" inline />
</Link>
@ -869,10 +879,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button
className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleShowReportDialog)}
aria-label={i18n.t("show_report_dialog")}
aria-label={I18NextService.i18n.t("show_report_dialog")}
>
<Icon classes="me-1" icon="flag" inline />
{i18n.t("create_report")}
{I18NextService.i18n.t("create_report")}
</button>
);
}
@ -882,14 +892,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button
className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleBlockPersonClick)}
aria-label={i18n.t("block_user")}
aria-label={I18NextService.i18n.t("block_user")}
>
{this.state.blockLoading ? (
<Spinner />
) : (
<Icon classes="me-1" icon="slash" inline />
)}
{i18n.t("block_user")}
{I18NextService.i18n.t("block_user")}
</button>
);
}
@ -899,17 +909,19 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button
className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
onClick={linkEvent(this, this.handleEditClick)}
aria-label={i18n.t("edit")}
aria-label={I18NextService.i18n.t("edit")}
>
<Icon classes="me-1" icon="edit" inline />
{i18n.t("edit")}
{I18NextService.i18n.t("edit")}
</button>
);
}
get deleteButton() {
const deleted = this.postView.post.deleted;
const label = !deleted ? i18n.t("delete") : i18n.t("restore");
const label = !deleted
? I18NextService.i18n.t("delete")
: I18NextService.i18n.t("restore");
return (
<button
className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
@ -937,8 +949,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button
className="btn btn-sm btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t("view_source")}
aria-label={i18n.t("view_source")}
data-tippy-content={I18NextService.i18n.t("view_source")}
aria-label={I18NextService.i18n.t("view_source")}
>
<Icon
icon="file-text"
@ -951,7 +963,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
get lockButton() {
const locked = this.postView.post.locked;
const label = locked ? i18n.t("unlock") : i18n.t("lock");
const label = locked
? I18NextService.i18n.t("unlock")
: I18NextService.i18n.t("lock");
return (
<button
className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
@ -977,13 +991,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
get featureButtons() {
const featuredCommunity = this.postView.post.featured_community;
const labelCommunity = featuredCommunity
? i18n.t("unfeature_from_community")
: i18n.t("feature_in_community");
? I18NextService.i18n.t("unfeature_from_community")
: I18NextService.i18n.t("feature_in_community");
const featuredLocal = this.postView.post.featured_local;
const labelLocal = featuredLocal
? i18n.t("unfeature_from_local")
: i18n.t("feature_in_local");
? I18NextService.i18n.t("unfeature_from_local")
: I18NextService.i18n.t("feature_in_local");
return (
<>
<li>
@ -1004,7 +1018,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
})}
inline
/>
{i18n.t("community")}
{I18NextService.i18n.t("community")}
</>
)}
</button>
@ -1028,7 +1042,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
})}
inline
/>
{i18n.t("local")}
{I18NextService.i18n.t("local")}
</>
)}
</button>
@ -1052,9 +1066,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{this.state.removeLoading ? (
<Spinner />
) : !removed ? (
i18n.t("remove")
I18NextService.i18n.t("remove")
) : (
i18n.t("restore")
I18NextService.i18n.t("restore")
)}
</button>
);
@ -1079,9 +1093,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this,
this.handleModBanFromCommunityShow
)}
aria-label={i18n.t("ban_from_community")}
aria-label={I18NextService.i18n.t("ban_from_community")}
>
{i18n.t("ban_from_community")}
{I18NextService.i18n.t("ban_from_community")}
</button>
) : (
<button
@ -1090,9 +1104,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this,
this.handleModBanFromCommunitySubmit
)}
aria-label={i18n.t("unban")}
aria-label={I18NextService.i18n.t("unban")}
>
{this.state.banLoading ? <Spinner /> : i18n.t("unban")}
{this.state.banLoading ? (
<Spinner />
) : (
I18NextService.i18n.t("unban")
)}
</button>
))}
{!post_view.creator_banned_from_community && (
@ -1101,16 +1119,16 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onClick={linkEvent(this, this.handleAddModToCommunity)}
aria-label={
this.creatorIsMod_
? i18n.t("remove_as_mod")
: i18n.t("appoint_as_mod")
? I18NextService.i18n.t("remove_as_mod")
: I18NextService.i18n.t("appoint_as_mod")
}
>
{this.state.addModLoading ? (
<Spinner />
) : this.creatorIsMod_ ? (
i18n.t("remove_as_mod")
I18NextService.i18n.t("remove_as_mod")
) : (
i18n.t("appoint_as_mod")
I18NextService.i18n.t("appoint_as_mod")
)}
</button>
)}
@ -1127,24 +1145,28 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this,
this.handleShowConfirmTransferCommunity
)}
aria-label={i18n.t("transfer_community")}
aria-label={I18NextService.i18n.t("transfer_community")}
>
{i18n.t("transfer_community")}
{I18NextService.i18n.t("transfer_community")}
</button>
) : (
<>
<button
className="d-inline-block me-1 btn btn-link btn-animate text-muted py-0"
aria-label={i18n.t("are_you_sure")}
aria-label={I18NextService.i18n.t("are_you_sure")}
>
{i18n.t("are_you_sure")}
{I18NextService.i18n.t("are_you_sure")}
</button>
<button
className="btn btn-link btn-animate text-muted py-0 d-inline-block me-1"
aria-label={i18n.t("yes")}
aria-label={I18NextService.i18n.t("yes")}
onClick={linkEvent(this, this.handleTransferCommunity)}
>
{this.state.transferLoading ? <Spinner /> : i18n.t("yes")}
{this.state.transferLoading ? (
<Spinner />
) : (
I18NextService.i18n.t("yes")
)}
</button>
<button
className="btn btn-link btn-animate text-muted py-0 d-inline-block"
@ -1152,9 +1174,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this,
this.handleCancelShowConfirmTransferCommunity
)}
aria-label={i18n.t("no")}
aria-label={I18NextService.i18n.t("no")}
>
{i18n.t("no")}
{I18NextService.i18n.t("no")}
</button>
</>
))}
@ -1167,36 +1189,36 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button
className="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModBanShow)}
aria-label={i18n.t("ban_from_site")}
aria-label={I18NextService.i18n.t("ban_from_site")}
>
{i18n.t("ban_from_site")}
{I18NextService.i18n.t("ban_from_site")}
</button>
) : (
<button
className="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModBanSubmit)}
aria-label={i18n.t("unban_from_site")}
aria-label={I18NextService.i18n.t("unban_from_site")}
>
{this.state.banLoading ? (
<Spinner />
) : (
i18n.t("unban_from_site")
I18NextService.i18n.t("unban_from_site")
)}
</button>
)}
<button
className="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handlePurgePersonShow)}
aria-label={i18n.t("purge_user")}
aria-label={I18NextService.i18n.t("purge_user")}
>
{i18n.t("purge_user")}
{I18NextService.i18n.t("purge_user")}
</button>
<button
className="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handlePurgePostShow)}
aria-label={i18n.t("purge_post")}
aria-label={I18NextService.i18n.t("purge_post")}
>
{i18n.t("purge_post")}
{I18NextService.i18n.t("purge_post")}
</button>
</>
)}
@ -1206,16 +1228,16 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onClick={linkEvent(this, this.handleAddAdmin)}
aria-label={
this.creatorIsAdmin_
? i18n.t("remove_as_admin")
: i18n.t("appoint_as_admin")
? I18NextService.i18n.t("remove_as_admin")
: I18NextService.i18n.t("appoint_as_admin")
}
>
{this.state.addAdminLoading ? (
<Spinner />
) : this.creatorIsAdmin_ ? (
i18n.t("remove_as_admin")
I18NextService.i18n.t("remove_as_admin")
) : (
i18n.t("appoint_as_admin")
I18NextService.i18n.t("appoint_as_admin")
)}
</button>
)}
@ -1230,8 +1252,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
const post = this.postView;
const purgeTypeText =
this.state.purgeType == PurgeType.Post
? i18n.t("purge_post")
: `${i18n.t("purge")} ${post.creator.name}`;
? I18NextService.i18n.t("purge_post")
: `${I18NextService.i18n.t("purge")} ${post.creator.name}`;
return (
<>
{this.state.showRemoveDialog && (
@ -1243,22 +1265,26 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
className="visually-hidden"
htmlFor="post-listing-remove-reason"
>
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id="post-listing-remove-reason"
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
value={this.state.removeReason}
onInput={linkEvent(this, this.handleModRemoveReasonChange)}
/>
<button
type="submit"
className="btn btn-secondary"
aria-label={i18n.t("remove_post")}
aria-label={I18NextService.i18n.t("remove_post")}
>
{this.state.removeLoading ? <Spinner /> : i18n.t("remove_post")}
{this.state.removeLoading ? (
<Spinner />
) : (
I18NextService.i18n.t("remove_post")
)}
</button>
</form>
)}
@ -1269,24 +1295,24 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
className="col-form-label"
htmlFor="post-listing-ban-reason"
>
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id="post-listing-ban-reason"
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)}
/>
<label className="col-form-label" htmlFor={`mod-ban-expires`}>
{i18n.t("expires")}
{I18NextService.i18n.t("expires")}
</label>
<input
type="number"
id={`mod-ban-expires`}
className="form-control me-2"
placeholder={i18n.t("number_of_days")}
placeholder={I18NextService.i18n.t("number_of_days")}
value={this.state.banExpireDays}
onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
/>
@ -1302,9 +1328,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<label
className="form-check-label"
htmlFor="mod-ban-remove-data"
title={i18n.t("remove_content_more")}
title={I18NextService.i18n.t("remove_content_more")}
>
{i18n.t("remove_content")}
{I18NextService.i18n.t("remove_content")}
</label>
</div>
</div>
@ -1312,19 +1338,19 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{/* TODO hold off on expires until later */}
{/* <div class="mb-3 row"> */}
{/* <label class="col-form-label">Expires</label> */}
{/* <input type="date" class="form-control me-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
{/* <input type="date" class="form-control me-2" placeholder={I18NextService.i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
{/* </div> */}
<div className="mb-3 row">
<button
type="submit"
className="btn btn-secondary"
aria-label={i18n.t("ban")}
aria-label={I18NextService.i18n.t("ban")}
>
{this.state.banLoading ? (
<Spinner />
) : (
<span>
{i18n.t("ban")} {post.creator.name}
{I18NextService.i18n.t("ban")} {post.creator.name}
</span>
)}
</button>
@ -1337,13 +1363,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onSubmit={linkEvent(this, this.handleReportSubmit)}
>
<label className="visually-hidden" htmlFor="post-report-reason">
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id="post-report-reason"
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
required
value={this.state.reportReason}
onInput={linkEvent(this, this.handleReportReasonChange)}
@ -1351,9 +1377,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<button
type="submit"
className="btn btn-secondary"
aria-label={i18n.t("create_report")}
aria-label={I18NextService.i18n.t("create_report")}
>
{this.state.reportLoading ? <Spinner /> : i18n.t("create_report")}
{this.state.reportLoading ? (
<Spinner />
) : (
I18NextService.i18n.t("create_report")
)}
</button>
</form>
)}
@ -1364,13 +1394,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
>
<PurgeWarning />
<label className="visually-hidden" htmlFor="purge-reason">
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id="purge-reason"
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
value={this.state.purgeReason}
onInput={linkEvent(this, this.handlePurgeReasonChange)}
/>
@ -1565,10 +1595,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
const body = post.body;
return body
? `${i18n.t("cross_posted_from")} ${post.ap_id}\n\n${body.replace(
/^/gm,
"> "
)}`
? `${I18NextService.i18n.t("cross_posted_from")} ${
post.ap_id
}\n\n${body.replace(/^/gm, "> ")}`
: undefined;
}
@ -1830,17 +1859,17 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
}
get pointsTippy(): string {
const points = i18n.t("number_of_points", {
const points = I18NextService.i18n.t("number_of_points", {
count: Number(this.postView.counts.score),
formattedCount: Number(this.postView.counts.score),
});
const upvotes = i18n.t("number_of_upvotes", {
const upvotes = I18NextService.i18n.t("number_of_upvotes", {
count: Number(this.postView.counts.upvotes),
formattedCount: Number(this.postView.counts.upvotes),
});
const downvotes = i18n.t("number_of_downvotes", {
const downvotes = I18NextService.i18n.t("number_of_downvotes", {
count: Number(this.postView.counts.downvotes),
formattedCount: Number(this.postView.counts.downvotes),
});

View file

@ -21,7 +21,7 @@ import {
SavePost,
TransferCommunity,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { PostListing } from "./post-listing";
interface PostListingsProps {
@ -101,7 +101,7 @@ export class PostListings extends Component<PostListingsProps, any> {
))
) : (
<>
<div>{i18n.t("no_posts")}</div>
<div>{I18NextService.i18n.t("no_posts")}</div>
{this.props.showCommunity && (
<T i18nKey="subscribe_to_communities">
#<Link to="/communities">#</Link>

View file

@ -2,7 +2,7 @@ import { myAuthRequired } from "@utils/app";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import { PostReportView, PostView, ResolvePostReport } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { Icon, Spinner } from "../common/icon";
import { PersonListing } from "../person/person-listing";
import { PostListing } from "./post-listing";
@ -37,7 +37,7 @@ export class PostReport extends Component<PostReportProps, PostReportState> {
const r = this.props.report;
const resolver = r.resolver;
const post = r.post;
const tippyContent = i18n.t(
const tippyContent = I18NextService.i18n.t(
r.post_report.resolved ? "unresolve_report" : "resolve_report"
);
@ -89,10 +89,11 @@ export class PostReport extends Component<PostReportProps, PostReportState> {
onTransferCommunity={() => {}}
/>
<div>
{i18n.t("reporter")}: <PersonListing person={r.creator} />
{I18NextService.i18n.t("reporter")}:{" "}
<PersonListing person={r.creator} />
</div>
<div>
{i18n.t("reason")}: {r.post_report.reason}
{I18NextService.i18n.t("reason")}: {r.post_report.reason}
</div>
{resolver && (
<div>

View file

@ -76,14 +76,12 @@ import {
TransferCommunity,
} from "lemmy-js-client";
import { commentTreeMaxDepth } from "../../config";
import { i18n } from "../../i18next";
import {
CommentNodeI,
CommentViewType,
InitialFetchRequest,
} from "../../interfaces";
import { UserService } from "../../services";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService, UserService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { setupTippy } from "../../tippy";
import { toast } from "../../toast";
@ -400,7 +398,7 @@ export class Post extends Component<any, PostState> {
className="btn btn-secondary d-inline-block mb-2 me-3"
onClick={linkEvent(this, this.handleShowSidebarMobile)}
>
{i18n.t("sidebar")}{" "}
{I18NextService.i18n.t("sidebar")}{" "}
<Icon
icon={
this.state.showSidebarMobile
@ -438,7 +436,7 @@ export class Post extends Component<any, PostState> {
this.state.commentSort === "Hot" && "active"
}`}
>
{i18n.t("hot")}
{I18NextService.i18n.t("hot")}
<input
type="radio"
className="btn-check"
@ -452,7 +450,7 @@ export class Post extends Component<any, PostState> {
this.state.commentSort === "Top" && "active"
}`}
>
{i18n.t("top")}
{I18NextService.i18n.t("top")}
<input
type="radio"
className="btn-check"
@ -466,7 +464,7 @@ export class Post extends Component<any, PostState> {
this.state.commentSort === "New" && "active"
}`}
>
{i18n.t("new")}
{I18NextService.i18n.t("new")}
<input
type="radio"
className="btn-check"
@ -480,7 +478,7 @@ export class Post extends Component<any, PostState> {
this.state.commentSort === "Old" && "active"
}`}
>
{i18n.t("old")}
{I18NextService.i18n.t("old")}
<input
type="radio"
className="btn-check"
@ -496,7 +494,7 @@ export class Post extends Component<any, PostState> {
this.state.commentViewType === CommentViewType.Flat && "active"
}`}
>
{i18n.t("chat")}
{I18NextService.i18n.t("chat")}
<input
type="radio"
className="btn-check"
@ -595,14 +593,14 @@ export class Post extends Component<any, PostState> {
className="ps-0 d-block btn btn-link text-muted"
onClick={linkEvent(this, this.handleViewPost)}
>
{i18n.t("view_all_comments")}
{I18NextService.i18n.t("view_all_comments")}
</button>
{showContextButton && (
<button
className="ps-0 d-block btn btn-link text-muted"
onClick={linkEvent(this, this.handleViewContext)}
>
{i18n.t("show_context")}
{I18NextService.i18n.t("show_context")}
</button>
)}
</>
@ -836,14 +834,14 @@ export class Post extends Component<any, PostState> {
async handleCommentReport(form: CreateCommentReport) {
const reportRes = await HttpService.client.createCommentReport(form);
if (reportRes.state == "success") {
toast(i18n.t("report_created"));
toast(I18NextService.i18n.t("report_created"));
}
}
async handlePostReport(form: CreatePostReport) {
const reportRes = await HttpService.client.createPostReport(form);
if (reportRes.state == "success") {
toast(i18n.t("report_created"));
toast(I18NextService.i18n.t("report_created"));
}
}
@ -982,7 +980,7 @@ export class Post extends Component<any, PostState> {
purgeItem(purgeRes: RequestState<PurgeItemResponse>) {
if (purgeRes.state == "success") {
toast(i18n.t("purge_success"));
toast(I18NextService.i18n.t("purge_success"));
this.context.router.history.push(`/`);
}
}

View file

@ -7,9 +7,8 @@ import {
GetPersonDetailsResponse,
GetSiteResponse,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { FirstLoadService } from "../../services/FirstLoadService";
import { FirstLoadService, I18NextService } from "../../services";
import { HttpService, RequestState } from "../../services/HttpService";
import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags";
@ -97,7 +96,7 @@ export class CreatePrivateMessage extends Component<
get documentTitle(): string {
if (this.state.recipientRes.state == "success") {
const name_ = this.state.recipientRes.data.person_view.person.name;
return `${i18n.t("create_private_message")} - ${name_}`;
return `${I18NextService.i18n.t("create_private_message")} - ${name_}`;
} else {
return "";
}
@ -116,7 +115,7 @@ export class CreatePrivateMessage extends Component<
return (
<div className="row">
<div className="col-12 col-lg-6 offset-lg-3 mb-4">
<h5>{i18n.t("create_private_message")}</h5>
<h5>{I18NextService.i18n.t("create_private_message")}</h5>
<PrivateMessageForm
onCreate={this.handlePrivateMessageCreate}
recipient={res.person_view.person}
@ -144,7 +143,7 @@ export class CreatePrivateMessage extends Component<
const res = await HttpService.client.createPrivateMessage(form);
if (res.state == "success") {
toast(i18n.t("message_sent"));
toast(I18NextService.i18n.t("message_sent"));
// Navigate to the front
this.context.router.history.push("/");

View file

@ -9,7 +9,7 @@ import {
PrivateMessageView,
} from "lemmy-js-client";
import { relTags } from "../../config";
import { i18n } from "../../i18next";
import { I18NextService } from "../../services";
import { setupTippy } from "../../tippy";
import { Icon, Spinner } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea";
@ -66,7 +66,7 @@ export class PrivateMessageForm extends Component<
// TODO
// <Prompt
// when={!this.state.loading && this.state.content}
// message={i18n.t("block_leaving")}
// message={I18NextService.i18n.t("block_leaving")}
// />
render() {
@ -83,7 +83,7 @@ export class PrivateMessageForm extends Component<
{!this.props.privateMessageView && (
<div className="mb-3 row">
<label className="col-sm-2 col-form-label">
{capitalizeFirstLetter(i18n.t("to"))}
{capitalizeFirstLetter(I18NextService.i18n.t("to"))}
</label>
<div className="col-sm-10 form-control-plaintext">
@ -93,12 +93,14 @@ export class PrivateMessageForm extends Component<
)}
<div className="mb-3 row">
<label className="col-sm-2 col-form-label">
{i18n.t("message")}
{I18NextService.i18n.t("message")}
<button
className="btn btn-link text-warning d-inline-block"
onClick={linkEvent(this, this.handleShowDisclaimer)}
data-tippy-content={i18n.t("private_message_disclaimer")}
aria-label={i18n.t("private_message_disclaimer")}
data-tippy-content={I18NextService.i18n.t(
"private_message_disclaimer"
)}
aria-label={I18NextService.i18n.t("private_message_disclaimer")}
>
<Icon icon="alert-triangle" classes="icon-inline" />
</button>
@ -142,9 +144,9 @@ export class PrivateMessageForm extends Component<
{this.state.loading ? (
<Spinner />
) : this.props.privateMessageView ? (
capitalizeFirstLetter(i18n.t("save"))
capitalizeFirstLetter(I18NextService.i18n.t("save"))
) : (
capitalizeFirstLetter(i18n.t("send_message"))
capitalizeFirstLetter(I18NextService.i18n.t("send_message"))
)}
</button>
{this.props.privateMessageView && (
@ -153,7 +155,7 @@ export class PrivateMessageForm extends Component<
className="btn btn-secondary"
onClick={linkEvent(this, this.handleCancel)}
>
{i18n.t("cancel")}
{I18NextService.i18n.t("cancel")}
</button>
)}
<ul className="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold">

View file

@ -5,8 +5,8 @@ import {
PrivateMessageReportView,
ResolvePrivateMessageReport,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { I18NextService } from "../../services";
import { Icon, Spinner } from "../common/icon";
import { PersonListing } from "../person/person-listing";
@ -39,28 +39,29 @@ export class PrivateMessageReport extends Component<Props, State> {
render() {
const r = this.props.report;
const pmr = r.private_message_report;
const tippyContent = i18n.t(
const tippyContent = I18NextService.i18n.t(
r.private_message_report.resolved ? "unresolve_report" : "resolve_report"
);
return (
<div className="private-message-report">
<div>
{i18n.t("creator")}:{" "}
{I18NextService.i18n.t("creator")}:{" "}
<PersonListing person={r.private_message_creator} />
</div>
<div>
{i18n.t("message")}:
{I18NextService.i18n.t("message")}:
<div
className="md-div"
dangerouslySetInnerHTML={mdToHtml(pmr.original_pm_text)}
/>
</div>
<div>
{i18n.t("reporter")}: <PersonListing person={r.creator} />
{I18NextService.i18n.t("reporter")}:{" "}
<PersonListing person={r.creator} />
</div>
<div>
{i18n.t("reason")}: {pmr.reason}
{I18NextService.i18n.t("reason")}: {pmr.reason}
</div>
{r.resolver && (
<div>

View file

@ -9,9 +9,8 @@ import {
Person,
PrivateMessageView,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { mdToHtml } from "../../markdown";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { Icon, Spinner } from "../common/icon";
import { MomentTime } from "../common/moment-time";
import { PersonListing } from "../person/person-listing";
@ -94,7 +93,9 @@ export class PrivateMessage extends Component<
<ul className="list-inline mb-0 text-muted small">
{/* TODO refactor this */}
<li className="list-inline-item">
{this.mine ? i18n.t("to") : i18n.t("from")}
{this.mine
? I18NextService.i18n.t("to")
: I18NextService.i18n.t("from")}
</li>
<li className="list-inline-item">
<PersonListing person={otherPerson} />
@ -148,13 +149,13 @@ export class PrivateMessage extends Component<
onClick={linkEvent(this, this.handleMarkRead)}
data-tippy-content={
message_view.private_message.read
? i18n.t("mark_as_unread")
: i18n.t("mark_as_read")
? I18NextService.i18n.t("mark_as_unread")
: I18NextService.i18n.t("mark_as_read")
}
aria-label={
message_view.private_message.read
? i18n.t("mark_as_unread")
: i18n.t("mark_as_read")
? I18NextService.i18n.t("mark_as_unread")
: I18NextService.i18n.t("mark_as_read")
}
>
{this.state.readLoading ? (
@ -175,8 +176,8 @@ export class PrivateMessage extends Component<
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleReplyClick)}
data-tippy-content={i18n.t("reply")}
aria-label={i18n.t("reply")}
data-tippy-content={I18NextService.i18n.t("reply")}
aria-label={I18NextService.i18n.t("reply")}
>
<Icon icon="reply1" classes="icon-inline" />
</button>
@ -189,8 +190,8 @@ export class PrivateMessage extends Component<
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t("edit")}
aria-label={i18n.t("edit")}
data-tippy-content={I18NextService.i18n.t("edit")}
aria-label={I18NextService.i18n.t("edit")}
>
<Icon icon="edit" classes="icon-inline" />
</button>
@ -201,13 +202,13 @@ export class PrivateMessage extends Component<
onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={
!message_view.private_message.deleted
? i18n.t("delete")
: i18n.t("restore")
? I18NextService.i18n.t("delete")
: I18NextService.i18n.t("restore")
}
aria-label={
!message_view.private_message.deleted
? i18n.t("delete")
: i18n.t("restore")
? I18NextService.i18n.t("delete")
: I18NextService.i18n.t("restore")
}
>
{this.state.deleteLoading ? (
@ -229,8 +230,8 @@ export class PrivateMessage extends Component<
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t("view_source")}
aria-label={i18n.t("view_source")}
data-tippy-content={I18NextService.i18n.t("view_source")}
aria-label={I18NextService.i18n.t("view_source")}
>
<Icon
icon="file-text"
@ -250,13 +251,13 @@ export class PrivateMessage extends Component<
onSubmit={linkEvent(this, this.handleReportSubmit)}
>
<label className="visually-hidden" htmlFor="pm-report-reason">
{i18n.t("reason")}
{I18NextService.i18n.t("reason")}
</label>
<input
type="text"
id="pm-report-reason"
className="form-control me-2"
placeholder={i18n.t("reason")}
placeholder={I18NextService.i18n.t("reason")}
required
value={this.state.reportReason}
onInput={linkEvent(this, this.handleReportReasonChange)}
@ -264,9 +265,13 @@ export class PrivateMessage extends Component<
<button
type="submit"
className="btn btn-secondary"
aria-label={i18n.t("create_report")}
aria-label={I18NextService.i18n.t("create_report")}
>
{this.state.reportLoading ? <Spinner /> : i18n.t("create_report")}
{this.state.reportLoading ? (
<Spinner />
) : (
I18NextService.i18n.t("create_report")
)}
</button>
</form>
)}
@ -287,8 +292,8 @@ export class PrivateMessage extends Component<
<button
className="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleShowReportDialog)}
data-tippy-content={i18n.t("show_report_dialog")}
aria-label={i18n.t("show_report_dialog")}
data-tippy-content={I18NextService.i18n.t("show_report_dialog")}
aria-label={I18NextService.i18n.t("show_report_dialog")}
>
<Icon icon="flag" inline />
</button>
@ -297,7 +302,9 @@ export class PrivateMessage extends Component<
get messageUnlessRemoved(): string {
const message = this.props.private_message_view.private_message;
return message.deleted ? `*${i18n.t("deleted")}*` : message.content;
return message.deleted
? `*${I18NextService.i18n.t("deleted")}*`
: message.content;
}
handleReplyClick(i: PrivateMessage) {

View file

@ -46,9 +46,8 @@ import {
SortType,
} from "lemmy-js-client";
import { fetchLimit } from "../config";
import { i18n } from "../i18next";
import { CommentViewType, InitialFetchRequest } from "../interfaces";
import { FirstLoadService } from "../services/FirstLoadService";
import { FirstLoadService, I18NextService } from "../services";
import { HttpService, RequestState } from "../services/HttpService";
import { CommentNodes } from "./comment/comment-nodes";
import { HtmlTags } from "./common/html-tags";
@ -184,13 +183,13 @@ const Filter = ({
return (
<div className="mb-3 col-sm-6">
<label className="col-form-label me-2" htmlFor={`${filterType}-filter`}>
{capitalizeFirstLetter(i18n.t(filterType))}
{capitalizeFirstLetter(I18NextService.i18n.t(filterType))}
</label>
<SearchableSelect
id={`${filterType}-filter`}
options={[
{
label: i18n.t("all"),
label: I18NextService.i18n.t("all"),
value: "0",
},
].concat(options)}
@ -228,7 +227,7 @@ function getListing(
return (
<>
<span>{listing}</span>
<span>{` - ${i18n.t(translationKey, {
<span>{` - ${I18NextService.i18n.t(translationKey, {
count: Number(count),
formattedCount: numToSI(count),
})}`}</span>
@ -448,7 +447,7 @@ export class Search extends Component<any, SearchState> {
get documentTitle(): string {
const { q } = getSearchQueryParams();
const name = this.state.siteRes.site_view.site.name;
return `${i18n.t("search")} - ${q ? `${q} - ` : ""}${name}`;
return `${I18NextService.i18n.t("search")} - ${q ? `${q} - ` : ""}${name}`;
}
render() {
@ -460,13 +459,13 @@ export class Search extends Component<any, SearchState> {
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
<h5>{i18n.t("search")}</h5>
<h5>{I18NextService.i18n.t("search")}</h5>
{this.selects}
{this.searchForm}
{this.displayResults(type)}
{this.resultsCount === 0 &&
this.state.searchRes.state === "success" && (
<span>{i18n.t("no_results")}</span>
<span>{I18NextService.i18n.t("no_results")}</span>
)}
<Paginator page={page} onChange={this.handlePageChange} />
</div>
@ -499,8 +498,8 @@ export class Search extends Component<any, SearchState> {
type="text"
className="form-control me-2 mb-2 col-sm-8"
value={this.state.searchText}
placeholder={`${i18n.t("search")}...`}
aria-label={i18n.t("search")}
placeholder={`${I18NextService.i18n.t("search")}...`}
aria-label={I18NextService.i18n.t("search")}
onInput={linkEvent(this, this.handleQChange)}
required
minLength={1}
@ -511,7 +510,7 @@ export class Search extends Component<any, SearchState> {
{this.state.searchRes.state === "loading" ? (
<Spinner />
) : (
<span>{i18n.t("search")}</span>
<span>{I18NextService.i18n.t("search")}</span>
)}
</button>
</div>
@ -540,14 +539,16 @@ export class Search extends Component<any, SearchState> {
value={type}
onChange={linkEvent(this, this.handleTypeChange)}
className="form-select d-inline-block w-auto mb-2"
aria-label={i18n.t("type")}
aria-label={I18NextService.i18n.t("type")}
>
<option disabled aria-hidden="true">
{i18n.t("type")}
{I18NextService.i18n.t("type")}
</option>
{searchTypes.map(option => (
<option value={option} key={option}>
{i18n.t(option.toString().toLowerCase() as NoOptionI18nKeys)}
{I18NextService.i18n.t(
option.toString().toLowerCase() as NoOptionI18nKeys
)}
</option>
))}
</select>

View file

@ -1,7 +1,7 @@
import { LemmyHttp } from "lemmy-js-client";
import { getHttpBase } from "../../shared/env";
import { i18n } from "../../shared/i18next";
import { toast } from "../../shared/toast";
import { I18NextService } from "./I18NextService";
type EmptyRequestState = {
state: "empty";
@ -62,7 +62,7 @@ class WrappedLemmyHttpClient {
};
} catch (error) {
console.error(`API error: ${error}`);
toast(i18n.t(error), "danger");
toast(I18NextService.i18n.t(error), "danger");
return {
state: "failed",
msg: error,

View file

@ -1,37 +1,37 @@
import { isBrowser } from "@utils/browser";
import i18next, { i18nTyped, Resource } from "i18next";
import { UserService } from "./services/UserService";
import { ar } from "./translations/ar";
import { bg } from "./translations/bg";
import { ca } from "./translations/ca";
import { cs } from "./translations/cs";
import { da } from "./translations/da";
import { de } from "./translations/de";
import { el } from "./translations/el";
import { en } from "./translations/en";
import { eo } from "./translations/eo";
import { es } from "./translations/es";
import { eu } from "./translations/eu";
import { fa } from "./translations/fa";
import { fi } from "./translations/fi";
import { fr } from "./translations/fr";
import { ga } from "./translations/ga";
import { gl } from "./translations/gl";
import { hr } from "./translations/hr";
import { id } from "./translations/id";
import { it } from "./translations/it";
import { ja } from "./translations/ja";
import { ko } from "./translations/ko";
import { nl } from "./translations/nl";
import { oc } from "./translations/oc";
import { pl } from "./translations/pl";
import { pt } from "./translations/pt";
import { pt_BR } from "./translations/pt_BR";
import { ru } from "./translations/ru";
import { sv } from "./translations/sv";
import { vi } from "./translations/vi";
import { zh } from "./translations/zh";
import { zh_Hant } from "./translations/zh_Hant";
import i18next, { Resource } from "i18next";
import { UserService } from "../services";
import { ar } from "../translations/ar";
import { bg } from "../translations/bg";
import { ca } from "../translations/ca";
import { cs } from "../translations/cs";
import { da } from "../translations/da";
import { de } from "../translations/de";
import { el } from "../translations/el";
import { en } from "../translations/en";
import { eo } from "../translations/eo";
import { es } from "../translations/es";
import { eu } from "../translations/eu";
import { fa } from "../translations/fa";
import { fi } from "../translations/fi";
import { fr } from "../translations/fr";
import { ga } from "../translations/ga";
import { gl } from "../translations/gl";
import { hr } from "../translations/hr";
import { id } from "../translations/id";
import { it } from "../translations/it";
import { ja } from "../translations/ja";
import { ko } from "../translations/ko";
import { nl } from "../translations/nl";
import { oc } from "../translations/oc";
import { pl } from "../translations/pl";
import { pt } from "../translations/pt";
import { pt_BR } from "../translations/pt_BR";
import { ru } from "../translations/ru";
import { sv } from "../translations/sv";
import { vi } from "../translations/vi";
import { zh } from "../translations/zh";
import { zh_Hant } from "../translations/zh_Hant";
export const languages = [
{ resource: ar, code: "ar", name: "العربية" },
@ -92,7 +92,13 @@ class LanguageDetector {
}
}
i18next.use(LanguageDetector).init({
export class I18NextService {
#i18n: typeof i18next;
static #instance: I18NextService;
private constructor() {
this.#i18n = i18next;
this.#i18n.use(LanguageDetector).init({
debug: false,
compatibilityJSON: "v3",
supportedLngs: languages.map(l => l.code),
@ -102,6 +108,14 @@ i18next.use(LanguageDetector).init({
fallbackLng: "en",
resources,
interpolation: { format },
});
});
}
export const i18n = i18next as i18nTyped;
static get #Instance() {
return this.#instance ?? (this.#instance = new this());
}
public static get i18n() {
return this.#Instance.#i18n;
}
}

View file

@ -5,8 +5,8 @@ import IsomorphicCookie from "isomorphic-cookie";
import jwt_decode from "jwt-decode";
import { LoginResponse, MyUserInfo } from "lemmy-js-client";
import { isHttps } from "../env";
import { i18n } from "../i18next";
import { toast } from "../toast";
import { I18NextService } from "./I18NextService";
interface Claims {
sub: number;
@ -32,7 +32,7 @@ export class UserService {
const expires = new Date();
expires.setDate(expires.getDate() + 365);
if (res.jwt) {
toast(i18n.t("logged_in"));
toast(I18NextService.i18n.t("logged_in"));
IsomorphicCookie.save("jwt", res.jwt, { expires, secure: isHttps() });
this.#setJwtInfo();
}
@ -58,7 +58,7 @@ export class UserService {
const msg = "No JWT cookie found";
if (throwErr && isBrowser()) {
console.error(msg);
toast(i18n.t("not_logged_in"), "danger");
toast(I18NextService.i18n.t("not_logged_in"), "danger");
}
return undefined;
// throw msg;

View file

@ -1,2 +1,5 @@
export { FirstLoadService } from "./FirstLoadService";
export { HistoryService } from "./HistoryService";
export { HttpService } from "./HttpService";
export { I18NextService } from "./I18NextService";
export { UserService } from "./UserService";

View file

@ -1,7 +1,7 @@
import { isBrowser } from "@utils/browser";
import { ThemeColor } from "@utils/types";
import Toastify from "toastify-js";
import { i18n } from "./i18next";
import { I18NextService } from "./services";
export function toast(text: string, background: ThemeColor = "success") {
if (isBrowser()) {
@ -18,13 +18,18 @@ export function toast(text: string, background: ThemeColor = "success") {
export function pictrsDeleteToast(filename: string, deleteUrl: string) {
if (isBrowser()) {
const clickToDeleteText = i18n.t("click_to_delete_picture", { filename });
const deletePictureText = i18n.t("picture_deleted", {
const clickToDeleteText = I18NextService.i18n.t("click_to_delete_picture", {
filename,
});
const failedDeletePictureText = i18n.t("failed_to_delete_picture", {
const deletePictureText = I18NextService.i18n.t("picture_deleted", {
filename,
});
const failedDeletePictureText = I18NextService.i18n.t(
"failed_to_delete_picture",
{
filename,
}
);
const backgroundColor = `var(--bs-light)`;

View file

@ -1,11 +1,10 @@
import { GetSiteResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { setupEmojiDataModel, setupMarkdown } from "../../markdown";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
export default function initializeSite(site?: GetSiteResponse) {
UserService.Instance.myUserInfo = site?.my_user;
i18n.changeLanguage();
I18NextService.i18n.changeLanguage();
if (site) {
setupEmojiDataModel(site.custom_emojis ?? []);
}

View file

@ -1,6 +1,5 @@
import { BlockCommunityResponse, MyUserInfo } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { toast } from "../../toast";
export default function updateCommunityBlock(
@ -13,12 +12,20 @@ export default function updateCommunityBlock(
person: myUserInfo.local_user_view.person,
community: data.community_view.community,
});
toast(`${i18n.t("blocked")} ${data.community_view.community.name}`);
toast(
`${I18NextService.i18n.t("blocked")} ${
data.community_view.community.name
}`
);
} else {
myUserInfo.community_blocks = myUserInfo.community_blocks.filter(
i => i.community.id !== data.community_view.community.id
);
toast(`${i18n.t("unblocked")} ${data.community_view.community.name}`);
toast(
`${I18NextService.i18n.t("unblocked")} ${
data.community_view.community.name
}`
);
}
}
}

View file

@ -1,6 +1,5 @@
import { BlockPersonResponse, MyUserInfo } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { I18NextService, UserService } from "../../services";
import { toast } from "../../toast";
export default function updatePersonBlock(
@ -13,12 +12,16 @@ export default function updatePersonBlock(
person: myUserInfo.local_user_view.person,
target: data.person_view.person,
});
toast(`${i18n.t("blocked")} ${data.person_view.person.name}`);
toast(
`${I18NextService.i18n.t("blocked")} ${data.person_view.person.name}`
);
} else {
myUserInfo.person_blocks = myUserInfo.person_blocks.filter(
i => i.target.id !== data.person_view.person.id
);
toast(`${i18n.t("unblocked")} ${data.person_view.person.name}`);
toast(
`${I18NextService.i18n.t("unblocked")} ${data.person_view.person.name}`
);
}
}
}