mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-12-27 13:21:26 +00:00
Merge branch 'LemmyNet:main' into added-darkly-compact-552
This commit is contained in:
commit
dfe394adca
175 changed files with 3040 additions and 2642 deletions
|
@ -1 +1 @@
|
|||
Subproject commit ddf0d3a4dcfba5eddbcdb702db2470b52abb3815
|
||||
Subproject commit a241fe1255a6363c7ae1ec5a09520c066745e6ce
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "lemmy-ui",
|
||||
"version": "0.18.0-rc.4",
|
||||
"version": "0.18.0-rc.5",
|
||||
"description": "An isomorphic UI for lemmy",
|
||||
"repository": "https://github.com/LemmyNet/lemmy-ui",
|
||||
"license": "AGPL-3.0",
|
||||
|
@ -66,7 +66,7 @@
|
|||
"inferno-server": "^8.1.1",
|
||||
"isomorphic-cookie": "^1.2.4",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"lemmy-js-client": "0.18.0-rc.1",
|
||||
"lemmy-js-client": "0.18.0-rc.2",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it-container": "^3.0.0",
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
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 { initializeSite } from "../shared/utils";
|
||||
import { HistoryService } from "../shared/services";
|
||||
|
||||
import "bootstrap/js/dist/collapse";
|
||||
import "bootstrap/js/dist/dropdown";
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { initializeSite, isAuthPath } from "@utils/app";
|
||||
import { ErrorPageData } from "@utils/types";
|
||||
import type { Request, Response } from "express";
|
||||
import { StaticRouter, matchPath } from "inferno-router";
|
||||
import { renderToString } from "inferno-server";
|
||||
|
@ -15,7 +17,6 @@ import {
|
|||
FailedRequestState,
|
||||
wrapClient,
|
||||
} from "../../shared/services/HttpService";
|
||||
import { ErrorPageData, initializeSite, isAuthPath } from "../../shared/utils";
|
||||
import { createSsrHtml } from "../utils/create-ssr-html";
|
||||
import { getErrorPageData } from "../utils/get-error-page-data";
|
||||
import { setForwardedHeaders } from "../utils/set-forwarded-headers";
|
||||
|
@ -28,7 +29,9 @@ export default async (req: Request, res: Response) => {
|
|||
const getSiteForm: GetSite = { auth };
|
||||
|
||||
const headers = setForwardedHeaders(req.headers);
|
||||
const client = wrapClient(new LemmyHttp(getHttpBaseInternal(), headers));
|
||||
const client = wrapClient(
|
||||
new LemmyHttp(getHttpBaseInternal(), { fetchFunction: fetch, headers })
|
||||
);
|
||||
|
||||
const { path, url, query } = req;
|
||||
|
||||
|
|
|
@ -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,9 +9,11 @@ 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(), headers));
|
||||
const client = wrapClient(
|
||||
new LemmyHttp(getHttpBaseInternal(), { fetchFunction: fetch, headers })
|
||||
);
|
||||
const site = await client.getSite({});
|
||||
|
||||
if (site.state === "success") {
|
||||
|
|
|
@ -25,7 +25,7 @@ if (!process.env["LEMMY_UI_DISABLE_CSP"] && !process.env["LEMMY_UI_DEBUG"]) {
|
|||
|
||||
server.get("/robots.txt", RobotsHandler);
|
||||
server.get("/service-worker.js", ServiceWorkerHandler);
|
||||
server.get("/manifest", ManifestHandler);
|
||||
server.get("/manifest.webmanifest", ManifestHandler);
|
||||
server.get("/css/themes/:name", ThemeHandler);
|
||||
server.get("/css/themelist", ThemesListHandler);
|
||||
server.get("/*", CatchAllHandler);
|
||||
|
|
|
@ -2,8 +2,8 @@ import { Helmet } from "inferno-helmet";
|
|||
import { renderToString } from "inferno-server";
|
||||
import serialize from "serialize-javascript";
|
||||
import sharp from "sharp";
|
||||
import { favIconPngUrl, favIconUrl } from "../../shared/config";
|
||||
import { ILemmyConfig, IsoDataOptionalSite } from "../../shared/interfaces";
|
||||
import { favIconPngUrl, favIconUrl } from "../../shared/utils";
|
||||
import { fetchIconPng } from "./fetch-icon-png";
|
||||
|
||||
const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || "";
|
||||
|
@ -77,7 +77,7 @@ export async function createSsrHtml(
|
|||
/>
|
||||
|
||||
<!-- Web app manifest -->
|
||||
<link rel="manifest" href="/manifest" />
|
||||
<link rel="manifest" href="/manifest.webmanifest" />
|
||||
<link rel="apple-touch-icon" href=${appleTouchIcon} />
|
||||
<link rel="apple-touch-startup-image" href=${appleTouchIcon} />
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ErrorPageData } from "@utils/types";
|
||||
import { GetSiteResponse } from "lemmy-js-client";
|
||||
import { ErrorPageData } from "../../shared/utils";
|
||||
|
||||
export function getErrorPageData(error: Error, site?: GetSiteResponse) {
|
||||
const errorPageData: ErrorPageData = {};
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Component, createRef, linkEvent, RefObject } from "inferno";
|
||||
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 { isAuthPath, setIsoData } from "../../utils";
|
||||
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} />
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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 { setIsoData } from "../../utils";
|
||||
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",
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Component } from "inferno";
|
||||
import { NavLink } from "inferno-router";
|
||||
import { GetSiteResponse } from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { docsUrl, joinLemmyUrl, repoUrl } from "../../utils";
|
||||
import { docsUrl, joinLemmyUrl, repoUrl } from "../../config";
|
||||
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>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { myAuth, showAvatars } from "@utils/app";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
import { poll } from "@utils/helpers";
|
||||
import { numToSI, poll } from "@utils/helpers";
|
||||
import { amAdmin, canCreateCommunity } from "@utils/roles";
|
||||
import { Component, createRef, linkEvent } from "inferno";
|
||||
import { NavLink } from "inferno-router";
|
||||
|
@ -9,17 +10,10 @@ import {
|
|||
GetUnreadCountResponse,
|
||||
GetUnreadRegistrationApplicationCountResponse,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { UserService } from "../../services";
|
||||
import { donateLemmyUrl, updateUnreadCountsInterval } from "../../config";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
import {
|
||||
donateLemmyUrl,
|
||||
myAuth,
|
||||
numToSI,
|
||||
showAvatars,
|
||||
toast,
|
||||
updateUnreadCountsInterval,
|
||||
} from "../../utils";
|
||||
import { toast } from "../../toast";
|
||||
import { Icon } from "../common/icon";
|
||||
import { PictrsImage } from "../common/pictrs-image";
|
||||
|
||||
|
@ -107,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),
|
||||
})}
|
||||
|
@ -126,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),
|
||||
})}
|
||||
|
@ -146,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", {
|
||||
count: Number(this.unreadApplicationCount),
|
||||
formattedCount: numToSI(this.unreadApplicationCount),
|
||||
})}
|
||||
title={I18NextService.i18n.t(
|
||||
"unread_registration_applications",
|
||||
{
|
||||
count: Number(this.unreadApplicationCount),
|
||||
formattedCount: numToSI(this.unreadApplicationCount),
|
||||
}
|
||||
)}
|
||||
onMouseUp={linkEvent(this, handleCollapseClick)}
|
||||
>
|
||||
<Icon icon="clipboard" />
|
||||
|
@ -167,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"
|
||||
|
@ -186,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">
|
||||
|
@ -203,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) && (
|
||||
|
@ -214,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>
|
||||
|
@ -239,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>
|
||||
|
@ -253,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>
|
||||
|
@ -269,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),
|
||||
})}
|
||||
|
@ -277,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),
|
||||
})}
|
||||
|
@ -294,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),
|
||||
})}
|
||||
|
@ -302,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),
|
||||
})}
|
||||
|
@ -320,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", {
|
||||
count: Number(this.unreadApplicationCount),
|
||||
formattedCount: numToSI(this.unreadApplicationCount),
|
||||
})}
|
||||
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", {
|
||||
count: Number(this.unreadApplicationCount),
|
||||
formattedCount: numToSI(this.unreadApplicationCount),
|
||||
})}
|
||||
{I18NextService.i18n.t(
|
||||
"unread_registration_applications",
|
||||
{
|
||||
count: Number(this.unreadApplicationCount),
|
||||
formattedCount: numToSI(
|
||||
this.unreadApplicationCount
|
||||
),
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
{this.unreadApplicationCount > 0 && (
|
||||
<span className="mx-1 badge text-bg-light">
|
||||
|
@ -362,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>
|
||||
|
@ -389,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>
|
||||
|
@ -402,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>
|
||||
</>
|
||||
|
@ -509,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
import { capitalizeFirstLetter } from "@utils/helpers";
|
||||
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 { capitalizeFirstLetter, myAuthRequired } from "../../utils";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { Icon } from "../common/icon";
|
||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||
|
||||
|
@ -57,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}
|
||||
/>
|
||||
|
@ -78,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) {
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
import {
|
||||
colorList,
|
||||
getCommentParentId,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
newVote,
|
||||
showScores,
|
||||
} from "@utils/app";
|
||||
import { futureDaysToUnixTime, numToSI } from "@utils/helpers";
|
||||
import {
|
||||
amCommunityCreator,
|
||||
canAdmin,
|
||||
|
@ -38,7 +47,7 @@ import {
|
|||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import moment from "moment";
|
||||
import { i18n } from "../../i18next";
|
||||
import { commentTreeMaxDepth } from "../../config";
|
||||
import {
|
||||
BanType,
|
||||
CommentNodeI,
|
||||
|
@ -46,21 +55,9 @@ import {
|
|||
PurgeType,
|
||||
VoteType,
|
||||
} from "../../interfaces";
|
||||
import { UserService } from "../../services";
|
||||
import {
|
||||
colorList,
|
||||
commentTreeMaxDepth,
|
||||
futureDaysToUnixTime,
|
||||
getCommentParentId,
|
||||
mdToHtml,
|
||||
mdToHtmlNoImages,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
newVote,
|
||||
numToSI,
|
||||
setupTippy,
|
||||
showScores,
|
||||
} from "../../utils";
|
||||
import { mdToHtml, mdToHtmlNoImages } from "../../markdown";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { Icon, PurgeWarning, Spinner } from "../common/icon";
|
||||
import { MomentTime } from "../common/moment-time";
|
||||
import { CommunityLink } from "../community/community-link";
|
||||
|
@ -243,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,
|
||||
|
@ -316,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}`}>
|
||||
|
@ -368,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
|
||||
|
@ -428,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 ? (
|
||||
|
@ -458,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 ? (
|
||||
|
@ -485,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 ? (
|
||||
|
@ -508,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>
|
||||
|
@ -517,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>
|
||||
|
@ -529,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>
|
||||
|
@ -539,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>
|
||||
|
@ -552,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 />
|
||||
|
@ -567,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 ? (
|
||||
|
@ -587,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"
|
||||
|
@ -602,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>
|
||||
|
@ -615,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 ? (
|
||||
|
@ -645,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
|
||||
|
@ -674,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
|
||||
|
@ -685,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>
|
||||
)}
|
||||
|
@ -707,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
|
||||
|
@ -718,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>
|
||||
))}
|
||||
|
@ -737,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"
|
||||
|
@ -759,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
|
||||
|
@ -773,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>
|
||||
</>
|
||||
))}
|
||||
|
@ -792,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"
|
||||
|
@ -810,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
|
||||
|
@ -825,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>
|
||||
</>
|
||||
))}
|
||||
|
@ -842,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"
|
||||
|
@ -852,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) ? (
|
||||
|
@ -864,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
|
||||
|
@ -875,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>
|
||||
)}
|
||||
|
@ -897,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"
|
||||
|
@ -916,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
|
||||
|
@ -930,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>
|
||||
</>
|
||||
))}
|
||||
|
@ -963,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
|
||||
|
@ -985,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>
|
||||
)}
|
||||
|
@ -1013,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>
|
||||
)}
|
||||
|
@ -1040,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)}
|
||||
/>
|
||||
|
@ -1054,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)}
|
||||
/>
|
||||
|
@ -1076,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>
|
||||
|
@ -1086,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>
|
||||
|
@ -1110,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)}
|
||||
/>
|
||||
|
@ -1211,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;
|
||||
|
@ -1257,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),
|
||||
});
|
||||
|
@ -1276,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { colorList } from "@utils/app";
|
||||
import classNames from "classnames";
|
||||
import { Component } from "inferno";
|
||||
import {
|
||||
|
@ -26,7 +27,6 @@ import {
|
|||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { CommentNodeI, CommentViewType } from "../../interfaces";
|
||||
import { colorList } from "../../utils";
|
||||
import { CommentNode } from "./comment-node";
|
||||
|
||||
interface CommentNodesProps {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
||||
import { T } from "inferno-i18next-dess";
|
||||
import {
|
||||
|
@ -5,9 +6,8 @@ import {
|
|||
CommentView,
|
||||
ResolveCommentReport,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { CommentNodeI, CommentViewType } from "../../interfaces";
|
||||
import { myAuthRequired } from "../../utils";
|
||||
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>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { numToSI } from "@utils/helpers";
|
||||
import { Link } from "inferno-router";
|
||||
import {
|
||||
CommunityAggregates,
|
||||
CommunityId,
|
||||
SiteAggregates,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { numToSI } from "../../utils";
|
||||
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", {
|
||||
count: Number(counts.users_active_day),
|
||||
formattedCount: numToSI(counts.users_active_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", {
|
||||
count: Number(counts.users_active_week),
|
||||
formattedCount: numToSI(counts.users_active_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", {
|
||||
count: Number(counts.users_active_month),
|
||||
formattedCount: numToSI(counts.users_active_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", {
|
||||
count: Number(counts.users_active_half_year),
|
||||
formattedCount: numToSI(counts.users_active_half_year),
|
||||
})}
|
||||
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>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { randomStr } from "@utils/helpers";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { CommentSortType } from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { randomStr, relTags, sortingHelpUrl } from "../../utils";
|
||||
import { relTags, sortingHelpUrl } from "../../config";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
interface CommentSortSelectProps {
|
||||
|
@ -41,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>
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Component } from "inferno";
|
||||
import { getEmojiMart } from "../../utils";
|
||||
import { getEmojiMart } from "../../markdown";
|
||||
|
||||
interface EmojiMartProps {
|
||||
onEmojiClick?(val: any): any;
|
||||
|
|
|
@ -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)}
|
||||
>
|
||||
|
@ -38,16 +38,18 @@ export class EmojiPicker extends Component<EmojiPickerProps, EmojiPickerState> {
|
|||
|
||||
{this.state.showPicker && (
|
||||
<>
|
||||
<div className="emoji-picker-container">
|
||||
<EmojiMart
|
||||
onEmojiClick={this.handleEmojiClick}
|
||||
pickerOptions={{}}
|
||||
></EmojiMart>
|
||||
<div className="position-relative">
|
||||
<div className="emoji-picker-container position-absolute w-100">
|
||||
<EmojiMart
|
||||
onEmojiClick={this.handleEmojiClick}
|
||||
pickerOptions={{}}
|
||||
></EmojiMart>
|
||||
</div>
|
||||
<div
|
||||
onClick={linkEvent(this, this.togglePicker)}
|
||||
className="click-away-container"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
onClick={linkEvent(this, this.togglePicker)}
|
||||
className="click-away-container"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { Component } from "inferno";
|
||||
import { setIsoData } from "../../utils";
|
||||
import { ErrorPage } from "../app/error-page";
|
||||
|
||||
class ErrorGuard extends Component<any, any> {
|
||||
|
|
|
@ -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 "../../utils";
|
||||
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} />
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { randomStr } from "@utils/helpers";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { i18n } from "../../i18next";
|
||||
import { HttpService, UserService } from "../../services";
|
||||
import { randomStr, toast } from "../../utils";
|
||||
import { HttpService, I18NextService, UserService } from "../../services";
|
||||
import { toast } from "../../toast";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
interface ImageUploadFormProps {
|
||||
|
@ -49,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>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { selectableLanguages } from "@utils/app";
|
||||
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 { randomStr, selectableLanguages } from "../../utils";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
interface LanguageSelectProps {
|
||||
|
@ -52,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">
|
||||
|
@ -63,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}`, {
|
||||
|
@ -102,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 => (
|
||||
|
|
|
@ -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 { randomStr } from "../../utils";
|
||||
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>
|
||||
);
|
||||
|
|
|
@ -1,26 +1,21 @@
|
|||
import { isBrowser } from "@utils/browser";
|
||||
import { numToSI, randomStr } from "@utils/helpers";
|
||||
import autosize from "autosize";
|
||||
import classNames from "classnames";
|
||||
import { NoOptionI18nKeys } from "i18next";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { Language } from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { HttpService, UserService } from "../../services";
|
||||
import {
|
||||
concurrentImageUpload,
|
||||
customEmojisLookup,
|
||||
markdownFieldCharacterLimit,
|
||||
markdownHelpUrl,
|
||||
maxUploadImages,
|
||||
mdToHtml,
|
||||
numToSI,
|
||||
pictrsDeleteToast,
|
||||
randomStr,
|
||||
relTags,
|
||||
setupTippy,
|
||||
setupTribute,
|
||||
toast,
|
||||
} from "../../utils";
|
||||
} from "../../config";
|
||||
import { customEmojisLookup, mdToHtml, setupTribute } from "../../markdown";
|
||||
import { HttpService, I18NextService, UserService } from "../../services";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { pictrsDeleteToast, toast } from "../../toast";
|
||||
import { EmojiPicker } from "./emoji-picker";
|
||||
import { Icon, Spinner } from "./icon";
|
||||
import { LanguageSelect } from "./language-select";
|
||||
|
@ -133,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
|
||||
|
@ -165,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 />
|
||||
|
@ -203,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" />
|
||||
|
@ -245,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", {
|
||||
uploaded: this.state.imageUploadStatus.uploaded,
|
||||
total: this.state.imageUploadStatus.total,
|
||||
})}
|
||||
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>
|
||||
|
@ -294,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 && (
|
||||
|
@ -304,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>
|
||||
|
@ -336,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}
|
||||
>
|
||||
|
@ -380,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),
|
||||
}),
|
||||
|
@ -681,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);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { capitalizeFirstLetter } from "@utils/helpers";
|
||||
import { Component } from "inferno";
|
||||
import moment from "moment";
|
||||
import { i18n } from "../../i18next";
|
||||
import { capitalizeFirstLetter } from "../../utils";
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ThemeColor } from "@utils/types";
|
||||
import classNames from "classnames";
|
||||
import { ThemeColor } from "../../utils";
|
||||
|
||||
interface ProgressBarProps {
|
||||
className?: string;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
||||
import { T } from "inferno-i18next-dess";
|
||||
import {
|
||||
ApproveRegistrationApplication,
|
||||
RegistrationApplicationView,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { mdToHtml, myAuthRequired } from "../../utils";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService } from "../../services";
|
||||
import { PersonListing } from "../person/person-listing";
|
||||
import { Spinner } from "./icon";
|
||||
import { MarkdownTextArea } from "./markdown-textarea";
|
||||
|
@ -60,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 && (
|
||||
|
@ -83,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)}
|
||||
|
@ -98,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
|
||||
|
@ -115,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>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Choice } from "@utils/types";
|
||||
import classNames from "classnames";
|
||||
import {
|
||||
ChangeEvent,
|
||||
|
@ -6,8 +7,7 @@ import {
|
|||
linkEvent,
|
||||
RefObject,
|
||||
} from "inferno";
|
||||
import { i18n } from "../../i18next";
|
||||
import { Choice } from "../../utils";
|
||||
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 &&
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { randomStr } from "@utils/helpers";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { SortType } from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { randomStr, relTags, sortingHelpUrl } from "../../utils";
|
||||
import { relTags, sortingHelpUrl } from "../../config";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
interface SortSelectProps {
|
||||
|
@ -40,43 +41,45 @@ 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={"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={"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>
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
import { getQueryParams, getQueryString } from "@utils/helpers";
|
||||
import {
|
||||
editCommunity,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
} from "@utils/app";
|
||||
import {
|
||||
getPageFromString,
|
||||
getQueryParams,
|
||||
getQueryString,
|
||||
numToSI,
|
||||
} from "@utils/helpers";
|
||||
import type { QueryParams } from "@utils/types";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import {
|
||||
CommunityResponse,
|
||||
|
@ -8,20 +21,9 @@ 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 {
|
||||
RouteDataResponse,
|
||||
editCommunity,
|
||||
getPageFromString,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
numToSI,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
} from "../../utils";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
import { ListingTypeSelect } from "../common/listing-type-select";
|
||||
|
@ -83,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
|
||||
}`;
|
||||
}
|
||||
|
@ -100,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
|
||||
|
@ -120,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>
|
||||
|
@ -166,7 +173,7 @@ export class Communities extends Component<any, CommunitiesState> {
|
|||
this.handleFollow
|
||||
)}
|
||||
>
|
||||
{i18n.t("unsubscribe")}
|
||||
{I18NextService.i18n.t("unsubscribe")}
|
||||
</button>
|
||||
)}
|
||||
{cv.subscribed === "NotSubscribed" && (
|
||||
|
@ -181,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>
|
||||
|
@ -227,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}
|
||||
|
@ -235,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>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
import { capitalizeFirstLetter, randomStr } from "@utils/helpers";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import {
|
||||
CommunityView,
|
||||
|
@ -5,8 +7,7 @@ import {
|
|||
EditCommunity,
|
||||
Language,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { capitalizeFirstLetter, myAuthRequired, randomStr } from "../../utils";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { ImageUploadForm } from "../common/image-upload-form";
|
||||
import { LanguageSelect } from "../common/language-select";
|
||||
|
@ -106,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>
|
||||
|
@ -124,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>
|
||||
|
@ -134,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>
|
||||
|
@ -157,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}
|
||||
|
@ -171,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}
|
||||
|
@ -184,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={[]}
|
||||
|
@ -201,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">
|
||||
|
@ -218,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">
|
||||
|
@ -253,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 && (
|
||||
|
@ -264,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>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { showAvatars } from "@utils/app";
|
||||
import { hostname } from "@utils/helpers";
|
||||
import { Component } from "inferno";
|
||||
import { Link } from "inferno-router";
|
||||
import { Community } from "lemmy-js-client";
|
||||
import { hostname, relTags, showAvatars } from "../../utils";
|
||||
import { relTags } from "../../config";
|
||||
import { PictrsImage } from "../common/pictrs-image";
|
||||
|
||||
interface CommunityLinkProps {
|
||||
|
|
|
@ -1,5 +1,28 @@
|
|||
import { getQueryParams, getQueryString } from "@utils/helpers";
|
||||
import {
|
||||
commentsToFlatNodes,
|
||||
communityRSSUrl,
|
||||
editComment,
|
||||
editPost,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
getCommentParentId,
|
||||
getDataTypeString,
|
||||
myAuth,
|
||||
postToCommentSortType,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
updateCommunityBlock,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
|
||||
import {
|
||||
getPageFromString,
|
||||
getQueryParams,
|
||||
getQueryString,
|
||||
} from "@utils/helpers";
|
||||
import type { QueryParams } from "@utils/types";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { RouteComponentProps } from "inferno-router/dist/Route";
|
||||
import {
|
||||
|
@ -54,40 +77,16 @@ import {
|
|||
SortType,
|
||||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { fetchLimit, relTags } from "../../config";
|
||||
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 {
|
||||
RouteDataResponse,
|
||||
commentsToFlatNodes,
|
||||
communityRSSUrl,
|
||||
editComment,
|
||||
editPost,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
fetchLimit,
|
||||
getCommentParentId,
|
||||
getDataTypeString,
|
||||
getPageFromString,
|
||||
myAuth,
|
||||
postToCommentSortType,
|
||||
relTags,
|
||||
restoreScrollPosition,
|
||||
saveScrollPosition,
|
||||
setIsoData,
|
||||
setupTippy,
|
||||
showLocal,
|
||||
toast,
|
||||
updateCommunityBlock,
|
||||
updatePersonBlock,
|
||||
} from "../../utils";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { toast } from "../../toast";
|
||||
import { CommentNodes } from "../comment/comment-nodes";
|
||||
import { BannerIconHeader } from "../common/banner-icon-header";
|
||||
import { DataTypeSelect } from "../common/data-type-select";
|
||||
|
@ -330,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
|
||||
|
@ -757,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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,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);
|
||||
}
|
||||
|
||||
|
@ -879,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(`/`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { enableNsfw, setIsoData } from "@utils/app";
|
||||
import { Component } from "inferno";
|
||||
import {
|
||||
CreateCommunity as CreateCommunityI,
|
||||
GetSiteResponse,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { HttpService } from "../../services/HttpService";
|
||||
import { enableNsfw, setIsoData } from "../../utils";
|
||||
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)}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
import { getUnixTime, hostname } from "@utils/helpers";
|
||||
import { amAdmin, amMod, amTopMod } from "@utils/roles";
|
||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
||||
import { T } from "inferno-i18next-dess";
|
||||
|
@ -15,9 +17,8 @@ import {
|
|||
PurgeCommunity,
|
||||
RemoveCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { UserService } from "../../services";
|
||||
import { getUnixTime, hostname, mdToHtml, myAuthRequired } from "../../utils";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { Badges } from "../common/badges";
|
||||
import { BannerIconHeader } from "../common/banner-icon-header";
|
||||
import { Icon, PurgeWarning, Spinner } from "../common/icon";
|
||||
|
@ -185,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>
|
||||
|
@ -198,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>
|
||||
|
@ -232,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} />
|
||||
|
@ -251,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>
|
||||
);
|
||||
}
|
||||
|
@ -268,7 +269,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
{this.state.followCommunityLoading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
i18n.t("subscribe")
|
||||
I18NextService.i18n.t("subscribe")
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
@ -286,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>
|
||||
)}
|
||||
</>
|
||||
|
@ -313,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>
|
||||
|
@ -329,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">
|
||||
|
@ -353,7 +356,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
this.handleCancelLeaveModTeamClick
|
||||
)}
|
||||
>
|
||||
{i18n.t("no")}
|
||||
{I18NextService.i18n.t("no")}
|
||||
</button>
|
||||
</li>
|
||||
</>
|
||||
|
@ -365,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 ? (
|
||||
|
@ -396,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
|
||||
|
@ -406,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>
|
||||
)}
|
||||
|
@ -424,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)}
|
||||
/>
|
||||
|
@ -438,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>
|
||||
|
@ -458,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)}
|
||||
/>
|
||||
|
@ -476,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>
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
import {
|
||||
fetchThemeList,
|
||||
myAuthRequired,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
} from "@utils/app";
|
||||
import { capitalizeFirstLetter } from "@utils/helpers";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import classNames from "classnames";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import {
|
||||
|
@ -10,21 +18,11 @@ import {
|
|||
GetSiteResponse,
|
||||
PersonView,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import { FirstLoadService } from "../../services/FirstLoadService";
|
||||
import { removeFromEmojiDataModel, updateEmojiDataModel } from "../../markdown";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
import {
|
||||
RouteDataResponse,
|
||||
capitalizeFirstLetter,
|
||||
fetchThemeList,
|
||||
myAuthRequired,
|
||||
removeFromEmojiDataModel,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
toast,
|
||||
updateEmojiDataModel,
|
||||
} from "../../utils";
|
||||
import { toast } from "../../toast";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
import Tabs from "../common/tabs";
|
||||
|
@ -109,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
|
||||
}`;
|
||||
}
|
||||
|
@ -130,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", {
|
||||
|
@ -182,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", {
|
||||
|
@ -203,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", {
|
||||
|
@ -254,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">
|
||||
|
@ -276,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>
|
||||
);
|
||||
|
@ -294,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">
|
||||
|
@ -320,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 });
|
||||
|
@ -341,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("/");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { myAuthRequired, setIsoData } from "@utils/app";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import {
|
||||
CreateCustomEmoji,
|
||||
|
@ -5,15 +6,9 @@ import {
|
|||
EditCustomEmoji,
|
||||
GetSiteResponse,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { HttpService } from "../../services/HttpService";
|
||||
import {
|
||||
customEmojisLookup,
|
||||
myAuthRequired,
|
||||
pictrsDeleteToast,
|
||||
setIsoData,
|
||||
toast,
|
||||
} from "../../utils";
|
||||
import { customEmojisLookup } from "../../markdown";
|
||||
import { HttpService, I18NextService } from "../../services";
|
||||
import { pictrsDeleteToast, toast } from "../../toast";
|
||||
import { EmojiMart } from "../common/emoji-mart";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Icon } from "../common/icon";
|
||||
|
@ -70,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() {
|
||||
|
@ -80,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
|
||||
|
@ -93,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>
|
||||
|
@ -219,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) ||
|
||||
|
@ -240,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"
|
||||
|
@ -261,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} />
|
||||
|
@ -284,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) {
|
||||
|
|
|
@ -1,6 +1,28 @@
|
|||
import { getQueryParams, getQueryString } from "@utils/helpers";
|
||||
import {
|
||||
commentsToFlatNodes,
|
||||
editComment,
|
||||
editPost,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
getCommentParentId,
|
||||
getDataTypeString,
|
||||
myAuth,
|
||||
postToCommentSortType,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
|
||||
import {
|
||||
getPageFromString,
|
||||
getQueryParams,
|
||||
getQueryString,
|
||||
getRandomFromList,
|
||||
} from "@utils/helpers";
|
||||
import { canCreateCommunity } from "@utils/roles";
|
||||
import type { QueryParams } from "@utils/types";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { NoOptionI18nKeys } from "i18next";
|
||||
import { Component, MouseEventHandler, linkEvent } from "inferno";
|
||||
import { T } from "inferno-i18next-dess";
|
||||
|
@ -50,41 +72,17 @@ import {
|
|||
SortType,
|
||||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { fetchLimit, relTags, trendingFetchLimit } from "../../config";
|
||||
import {
|
||||
CommentViewType,
|
||||
DataType,
|
||||
InitialFetchRequest,
|
||||
} from "../../interfaces";
|
||||
import { UserService } from "../../services";
|
||||
import { FirstLoadService } from "../../services/FirstLoadService";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { FirstLoadService, I18NextService, UserService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
import {
|
||||
RouteDataResponse,
|
||||
commentsToFlatNodes,
|
||||
editComment,
|
||||
editPost,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
fetchLimit,
|
||||
getCommentParentId,
|
||||
getDataTypeString,
|
||||
getPageFromString,
|
||||
getRandomFromList,
|
||||
mdToHtml,
|
||||
myAuth,
|
||||
postToCommentSortType,
|
||||
relTags,
|
||||
restoreScrollPosition,
|
||||
saveScrollPosition,
|
||||
setIsoData,
|
||||
setupTippy,
|
||||
showLocal,
|
||||
toast,
|
||||
trendingFetchLimit,
|
||||
updatePersonBlock,
|
||||
} from "../../utils";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { toast } from "../../toast";
|
||||
import { CommentNodes } from "../comment/comment-nodes";
|
||||
import { DataTypeSelect } from "../common/data-type-select";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
|
@ -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(`/`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { Component } from "inferno";
|
||||
import {
|
||||
GetFederatedInstancesResponse,
|
||||
GetSiteResponse,
|
||||
Instance,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { relTags } from "../../config";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import { FirstLoadService } from "../../services/FirstLoadService";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
import { RouteDataResponse, relTags, setIsoData } from "../../utils";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
|
||||
|
@ -68,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() {
|
||||
|
@ -84,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>
|
||||
)}
|
||||
|
@ -125,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>
|
||||
|
@ -146,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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { Component } from "inferno";
|
||||
import { GetSiteResponse } from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { mdToHtml, setIsoData } from "../../utils";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService } from "../../services";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
|
||||
interface LegalState {
|
||||
|
@ -19,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() {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { myAuth, setIsoData } from "@utils/app";
|
||||
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 { myAuth, setIsoData, toast, validEmail } from "../../utils";
|
||||
import { toast } from "../../toast";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
|
||||
|
@ -41,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 {
|
||||
|
@ -66,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
|
||||
|
@ -89,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
|
||||
|
@ -110,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>
|
||||
|
@ -122,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
|
||||
|
@ -144,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>
|
||||
|
@ -170,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 } });
|
||||
|
@ -218,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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
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 { capitalizeFirstLetter, myAuthRequired } from "../../utils";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Spinner } from "../common/icon";
|
||||
import Tabs from "../common/tabs";
|
||||
|
||||
|
@ -56,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"
|
||||
|
@ -67,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"
|
||||
|
@ -140,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", {
|
||||
|
@ -175,7 +180,7 @@ export default class RateLimitsForm extends Component<
|
|||
{this.props.loading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
capitalizeFirstLetter(i18n.t("save"))
|
||||
capitalizeFirstLetter(I18NextService.i18n.t("save"))
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { fetchThemeList, setIsoData } from "@utils/app";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { Helmet } from "inferno-helmet";
|
||||
import {
|
||||
|
@ -6,10 +7,8 @@ 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 { fetchThemeList, setIsoData } from "../../utils";
|
||||
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>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { myAuth, setIsoData } from "@utils/app";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
import { validEmail } from "@utils/helpers";
|
||||
import { Options, passwordStrength } from "check-password-strength";
|
||||
import { NoOptionI18nKeys } from "i18next";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
|
@ -10,17 +12,11 @@ import {
|
|||
LoginResponse,
|
||||
SiteView,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { UserService } from "../../services";
|
||||
import { joinLemmyUrl } from "../../config";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
import {
|
||||
joinLemmyUrl,
|
||||
mdToHtml,
|
||||
myAuth,
|
||||
setIsoData,
|
||||
toast,
|
||||
validEmail,
|
||||
} from "../../utils";
|
||||
import { toast } from "../../toast";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||
|
@ -116,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"
|
||||
);
|
||||
}
|
||||
|
@ -162,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">
|
||||
|
@ -175,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
|
||||
|
@ -191,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"
|
||||
|
@ -205,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>
|
||||
|
@ -216,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
|
||||
|
@ -232,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>
|
||||
|
@ -243,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
|
||||
|
@ -265,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
|
||||
|
@ -283,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
|
||||
|
@ -309,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>
|
||||
|
@ -348,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>
|
||||
|
@ -387,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}
|
||||
|
@ -477,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("/");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
import { capitalizeFirstLetter, validInstanceTLD } from "@utils/helpers";
|
||||
import {
|
||||
Component,
|
||||
InfernoKeyboardEvent,
|
||||
|
@ -11,12 +13,7 @@ import {
|
|||
Instance,
|
||||
ListingType,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import {
|
||||
capitalizeFirstLetter,
|
||||
myAuthRequired,
|
||||
validInstanceTLD,
|
||||
} from "../../utils";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { ImageUploadForm } from "../common/image-upload-form";
|
||||
import { LanguageSelect } from "../common/language-select";
|
||||
|
@ -139,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
|
||||
|
@ -160,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}
|
||||
|
@ -170,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}
|
||||
|
@ -180,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
|
||||
|
@ -194,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}
|
||||
|
@ -207,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
|
||||
|
@ -233,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>
|
||||
|
@ -252,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>
|
||||
|
@ -263,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"
|
||||
|
@ -272,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
|
||||
|
@ -312,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>
|
||||
|
@ -334,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>
|
||||
|
@ -356,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>
|
||||
|
@ -375,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>
|
||||
|
@ -386,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"
|
||||
|
@ -394,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}
|
||||
|
@ -406,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
|
||||
|
@ -432,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>
|
||||
|
@ -451,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>
|
||||
|
@ -461,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
|
||||
|
@ -488,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
|
||||
|
@ -515,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>
|
||||
|
@ -540,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>
|
||||
|
@ -550,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
|
||||
|
@ -582,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>
|
||||
|
@ -594,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"
|
||||
|
@ -602,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>
|
||||
|
@ -619,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>
|
||||
|
@ -637,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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Component, linkEvent } from "inferno";
|
||||
import { PersonView, Site, SiteAggregates } from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { mdToHtml } from "../../utils";
|
||||
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} />
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
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 { capitalizeFirstLetter, myAuthRequired } from "../../utils";
|
||||
import { I18NextService } from "../../services";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||
|
@ -26,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() {
|
||||
|
@ -36,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">
|
||||
|
@ -67,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>
|
||||
|
@ -79,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>
|
||||
|
@ -95,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>
|
||||
|
@ -110,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>
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
import { debounce, getQueryParams, getQueryString } from "@utils/helpers";
|
||||
import {
|
||||
fetchUsers,
|
||||
getUpdatedSearchId,
|
||||
myAuth,
|
||||
personToChoice,
|
||||
setIsoData,
|
||||
} from "@utils/app";
|
||||
import {
|
||||
debounce,
|
||||
getIdFromString,
|
||||
getPageFromString,
|
||||
getQueryParams,
|
||||
getQueryString,
|
||||
} from "@utils/helpers";
|
||||
import { amAdmin, amMod } from "@utils/roles";
|
||||
import type { QueryParams } from "@utils/types";
|
||||
import { Choice, RouteDataResponse } from "@utils/types";
|
||||
import { NoOptionI18nKeys } from "i18next";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { T } from "inferno-i18next-dess";
|
||||
|
@ -31,22 +45,10 @@ import {
|
|||
Person,
|
||||
} from "lemmy-js-client";
|
||||
import moment from "moment";
|
||||
import { i18n } from "../i18next";
|
||||
import { fetchLimit } from "../config";
|
||||
import { InitialFetchRequest } from "../interfaces";
|
||||
import { FirstLoadService } from "../services/FirstLoadService";
|
||||
import { FirstLoadService, I18NextService } from "../services";
|
||||
import { HttpService, RequestState } from "../services/HttpService";
|
||||
import {
|
||||
Choice,
|
||||
RouteDataResponse,
|
||||
fetchLimit,
|
||||
fetchUsers,
|
||||
getIdFromString,
|
||||
getPageFromString,
|
||||
getUpdatedSearchId,
|
||||
myAuth,
|
||||
personToChoice,
|
||||
setIsoData,
|
||||
} from "../utils";
|
||||
import { HtmlTags } from "./common/html-tags";
|
||||
import { Icon, Spinner } from "./common/icon";
|
||||
import { MomentTime } from "./common/moment-time";
|
||||
|
@ -583,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)}
|
||||
|
@ -721,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 {
|
||||
|
@ -767,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">
|
||||
|
@ -779,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>
|
||||
|
@ -845,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}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
import {
|
||||
commentsToFlatNodes,
|
||||
editCommentReply,
|
||||
editMention,
|
||||
editPrivateMessage,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
getCommentParentId,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
setIsoData,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import {
|
||||
AddAdmin,
|
||||
|
@ -44,28 +58,11 @@ import {
|
|||
SaveComment,
|
||||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { fetchLimit, relTags } from "../../config";
|
||||
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 {
|
||||
RouteDataResponse,
|
||||
commentsToFlatNodes,
|
||||
editCommentReply,
|
||||
editMention,
|
||||
editPrivateMessage,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
fetchLimit,
|
||||
getCommentParentId,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
relTags,
|
||||
setIsoData,
|
||||
toast,
|
||||
updatePersonBlock,
|
||||
} from "../../utils";
|
||||
import { toast } from "../../toast";
|
||||
import { CommentNodes } from "../comment/comment-nodes";
|
||||
import { CommentSortSelect } from "../common/comment-sort-select";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
|
@ -188,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}`
|
||||
: "";
|
||||
}
|
||||
|
||||
|
@ -224,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}>
|
||||
|
@ -246,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>
|
||||
)}
|
||||
|
@ -297,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
|
||||
|
@ -311,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>
|
||||
);
|
||||
|
@ -332,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
|
||||
|
@ -346,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
|
||||
|
@ -360,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
|
||||
|
@ -374,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>
|
||||
);
|
||||
|
@ -827,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);
|
||||
}
|
||||
|
||||
|
@ -838,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");
|
||||
|
@ -850,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);
|
||||
}
|
||||
}
|
||||
|
@ -858,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);
|
||||
}
|
||||
}
|
||||
|
@ -893,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) {
|
||||
|
@ -1005,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(`/`);
|
||||
}
|
||||
}
|
||||
|
@ -1014,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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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 { capitalizeFirstLetter, myAuth, setIsoData } from "../../utils";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
|
||||
|
@ -33,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
|
||||
}`;
|
||||
}
|
||||
|
@ -47,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>
|
||||
|
@ -60,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
|
||||
|
@ -76,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
|
||||
|
@ -96,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>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { commentsToFlatNodes } from "@utils/app";
|
||||
import { Component } from "inferno";
|
||||
import {
|
||||
AddAdmin,
|
||||
|
@ -37,7 +38,7 @@ import {
|
|||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { CommentViewType, PersonDetailsView } from "../../interfaces";
|
||||
import { commentsToFlatNodes, setupTippy } from "../../utils";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { CommentNodes } from "../comment/comment-nodes";
|
||||
import { Paginator } from "../common/paginator";
|
||||
import { PostListing } from "../post/post-listing";
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { showAvatars } from "@utils/app";
|
||||
import { hostname, isCakeDay } from "@utils/helpers";
|
||||
import classNames from "classnames";
|
||||
import { Component } from "inferno";
|
||||
import { Link } from "inferno-router";
|
||||
import { Person } from "lemmy-js-client";
|
||||
import { hostname, isCakeDay, relTags, showAvatars } from "../../utils";
|
||||
import { relTags } from "../../config";
|
||||
import { PictrsImage } from "../common/pictrs-image";
|
||||
import { CakeDay } from "./cake-day";
|
||||
|
||||
|
|
|
@ -1,6 +1,27 @@
|
|||
import { getQueryParams, getQueryString } from "@utils/helpers";
|
||||
import {
|
||||
editComment,
|
||||
editPost,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
getCommentParentId,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
setIsoData,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
|
||||
import {
|
||||
capitalizeFirstLetter,
|
||||
futureDaysToUnixTime,
|
||||
getPageFromString,
|
||||
getQueryParams,
|
||||
getQueryString,
|
||||
numToSI,
|
||||
} from "@utils/helpers";
|
||||
import { canMod, isAdmin, isBanned } from "@utils/roles";
|
||||
import type { QueryParams } from "@utils/types";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import classNames from "classnames";
|
||||
import { NoOptionI18nKeys } from "i18next";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
|
@ -50,35 +71,13 @@ import {
|
|||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import moment from "moment";
|
||||
import { i18n } from "../../i18next";
|
||||
import { fetchLimit, relTags } from "../../config";
|
||||
import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
|
||||
import { UserService } from "../../services";
|
||||
import { FirstLoadService } from "../../services/FirstLoadService";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { FirstLoadService, I18NextService, UserService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
import {
|
||||
RouteDataResponse,
|
||||
capitalizeFirstLetter,
|
||||
editComment,
|
||||
editPost,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
fetchLimit,
|
||||
futureDaysToUnixTime,
|
||||
getCommentParentId,
|
||||
getPageFromString,
|
||||
mdToHtml,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
numToSI,
|
||||
relTags,
|
||||
restoreScrollPosition,
|
||||
saveScrollPosition,
|
||||
setIsoData,
|
||||
setupTippy,
|
||||
toast,
|
||||
updatePersonBlock,
|
||||
} from "../../utils";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { toast } from "../../toast";
|
||||
import { BannerIconHeader } from "../common/banner-icon-header";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
|
@ -136,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}>
|
||||
|
@ -421,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>
|
||||
);
|
||||
}
|
||||
|
@ -484,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>
|
||||
|
@ -515,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={
|
||||
|
@ -523,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
|
||||
|
@ -535,7 +534,7 @@ export class Profile extends Component<
|
|||
this.handleUnblockPerson
|
||||
)}
|
||||
>
|
||||
{i18n.t("unblock_user")}
|
||||
{I18NextService.i18n.t("unblock_user")}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
|
@ -547,7 +546,7 @@ export class Profile extends Component<
|
|||
this.handleBlockPerson
|
||||
)}
|
||||
>
|
||||
{i18n.t("block_user")}
|
||||
{I18NextService.i18n.t("block_user")}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
|
@ -562,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
|
||||
|
@ -572,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>
|
||||
|
@ -589,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),
|
||||
})}
|
||||
|
@ -603,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
|
||||
|
@ -613,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()
|
||||
|
@ -622,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>
|
||||
|
@ -640,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)}
|
||||
/>
|
||||
|
@ -673,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>
|
||||
|
@ -683,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>
|
||||
|
@ -903,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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -934,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) {
|
||||
|
@ -998,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(`/`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
import {
|
||||
editRegistrationApplication,
|
||||
myAuthRequired,
|
||||
setIsoData,
|
||||
} from "@utils/app";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import {
|
||||
ApproveRegistrationApplication,
|
||||
|
@ -5,19 +11,11 @@ import {
|
|||
ListRegistrationApplicationsResponse,
|
||||
RegistrationApplicationView,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { fetchLimit } from "../../config";
|
||||
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 {
|
||||
RouteDataResponse,
|
||||
editRegistrationApplication,
|
||||
fetchLimit,
|
||||
myAuthRequired,
|
||||
setIsoData,
|
||||
setupTippy,
|
||||
} from "../../utils";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
import { Paginator } from "../common/paginator";
|
||||
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
import {
|
||||
editCommentReport,
|
||||
editPostReport,
|
||||
editPrivateMessageReport,
|
||||
myAuthRequired,
|
||||
setIsoData,
|
||||
} from "@utils/app";
|
||||
import { amAdmin } from "@utils/roles";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import {
|
||||
CommentReportResponse,
|
||||
|
@ -18,20 +26,15 @@ import {
|
|||
ResolvePostReport,
|
||||
ResolvePrivateMessageReport,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { fetchLimit } from "../../config";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import { HttpService, UserService } from "../../services";
|
||||
import { FirstLoadService } from "../../services/FirstLoadService";
|
||||
import { RequestState } from "../../services/HttpService";
|
||||
import {
|
||||
RouteDataResponse,
|
||||
editCommentReport,
|
||||
editPostReport,
|
||||
editPrivateMessageReport,
|
||||
fetchLimit,
|
||||
myAuthRequired,
|
||||
setIsoData,
|
||||
} from "../../utils";
|
||||
FirstLoadService,
|
||||
HttpService,
|
||||
I18NextService,
|
||||
UserService,
|
||||
} from "../../services";
|
||||
import { RequestState } from "../../services/HttpService";
|
||||
import { CommentReport } from "../comment/comment-report";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
|
@ -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>
|
||||
|
|
|
@ -1,4 +1,19 @@
|
|||
import { debounce } from "@utils/helpers";
|
||||
import {
|
||||
communityToChoice,
|
||||
fetchCommunities,
|
||||
fetchThemeList,
|
||||
fetchUsers,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
personToChoice,
|
||||
setIsoData,
|
||||
setTheme,
|
||||
showLocal,
|
||||
updateCommunityBlock,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
import { capitalizeFirstLetter, debounce } from "@utils/helpers";
|
||||
import { Choice } from "@utils/types";
|
||||
import classNames from "classnames";
|
||||
import { NoOptionI18nKeys } from "i18next";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
|
@ -13,30 +28,12 @@ import {
|
|||
PersonBlockView,
|
||||
SortType,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n, languages } from "../../i18next";
|
||||
import { elementUrl, emDash, relTags } from "../../config";
|
||||
import { UserService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
import {
|
||||
Choice,
|
||||
capitalizeFirstLetter,
|
||||
communityToChoice,
|
||||
elementUrl,
|
||||
emDash,
|
||||
fetchCommunities,
|
||||
fetchThemeList,
|
||||
fetchUsers,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
personToChoice,
|
||||
relTags,
|
||||
setIsoData,
|
||||
setTheme,
|
||||
setupTippy,
|
||||
showLocal,
|
||||
toast,
|
||||
updateCommunityBlock,
|
||||
updatePersonBlock,
|
||||
} from "../../utils";
|
||||
import { I18NextService, languages } from "../../services/I18NextService";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { toast } from "../../toast";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { ImageUploadForm } from "../common/image-upload-form";
|
||||
|
@ -116,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
|
||||
|
@ -236,7 +233,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return i18n.t("settings");
|
||||
return I18NextService.i18n.t("settings");
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -252,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,
|
||||
},
|
||||
]}
|
||||
|
@ -319,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
|
||||
|
@ -342,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
|
||||
|
@ -361,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
|
||||
|
@ -383,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>
|
||||
|
@ -412,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}>
|
||||
|
@ -424,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>
|
||||
|
@ -456,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}>
|
||||
|
@ -468,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>
|
||||
|
@ -485,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="^(?!@)(.+)$"
|
||||
|
@ -506,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
|
||||
|
@ -521,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}
|
||||
|
@ -538,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">
|
||||
|
@ -555,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}
|
||||
|
@ -569,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}
|
||||
|
@ -582,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
|
||||
|
@ -592,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>
|
||||
|
@ -619,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
|
||||
|
@ -629,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}
|
||||
|
@ -641,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_={
|
||||
|
@ -656,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
|
||||
|
@ -677,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>
|
||||
|
@ -691,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>
|
||||
|
@ -705,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>
|
||||
|
@ -719,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>
|
||||
|
@ -736,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>
|
||||
|
@ -753,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>
|
||||
|
@ -770,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>
|
||||
|
@ -793,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>
|
||||
|
@ -803,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>
|
||||
|
@ -816,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"
|
||||
|
@ -842,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
|
||||
|
@ -852,7 +857,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
this.handleDeleteAccountShowConfirmToggle
|
||||
)}
|
||||
>
|
||||
{i18n.t("cancel")}
|
||||
{I18NextService.i18n.t("cancel")}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
@ -879,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>
|
||||
|
@ -889,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">
|
||||
|
@ -904,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>
|
||||
|
@ -1053,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));
|
||||
}
|
||||
|
@ -1081,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)
|
||||
|
@ -1171,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);
|
||||
}
|
||||
|
||||
|
@ -1194,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 });
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
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 { setIsoData, toast } from "../../utils";
|
||||
import { toast } from "../../toast";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
|
||||
|
@ -35,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");
|
||||
}
|
||||
}
|
||||
|
@ -45,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
|
||||
}`;
|
||||
}
|
||||
|
@ -59,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 />
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { getQueryParams } from "@utils/helpers";
|
||||
import { enableDownvotes, enableNsfw, myAuth, setIsoData } from "@utils/app";
|
||||
import { getIdFromString, getQueryParams } from "@utils/helpers";
|
||||
import type { QueryParams } from "@utils/types";
|
||||
import { Choice, RouteDataResponse } from "@utils/types";
|
||||
import { Component } from "inferno";
|
||||
import { RouteComponentProps } from "inferno-router/dist/Route";
|
||||
import {
|
||||
|
@ -9,23 +11,13 @@ 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,
|
||||
WrappedLemmyHttp,
|
||||
} from "../../services/HttpService";
|
||||
import {
|
||||
Choice,
|
||||
RouteDataResponse,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
getIdFromString,
|
||||
myAuth,
|
||||
setIsoData,
|
||||
} from "../../utils";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
import { PostForm } from "./post-form";
|
||||
|
@ -150,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
|
||||
}`;
|
||||
}
|
||||
|
@ -178,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}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Component, linkEvent } from "inferno";
|
||||
import { Post } from "lemmy-js-client";
|
||||
import * as sanitizeHtml from "sanitize-html";
|
||||
import { i18n } from "../../i18next";
|
||||
import { relTags } from "../../utils";
|
||||
import { relTags } from "../../config";
|
||||
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>
|
||||
|
@ -75,10 +75,14 @@ export class MetadataCard extends Component<
|
|||
</div>
|
||||
)}
|
||||
{this.state.expanded && post.embed_video_url && (
|
||||
<iframe
|
||||
className="post-metadata-iframe"
|
||||
src={post.embed_video_url}
|
||||
></iframe>
|
||||
<div className="ratio ratio-16x9">
|
||||
<iframe
|
||||
allowFullScreen
|
||||
className="post-metadata-iframe"
|
||||
src={post.embed_video_url}
|
||||
title={post.embed_title}
|
||||
></iframe>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,18 @@
|
|||
import { debounce } from "@utils/helpers";
|
||||
import {
|
||||
communityToChoice,
|
||||
fetchCommunities,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
} from "@utils/app";
|
||||
import {
|
||||
capitalizeFirstLetter,
|
||||
debounce,
|
||||
getIdFromString,
|
||||
validTitle,
|
||||
validURL,
|
||||
} from "@utils/helpers";
|
||||
import { isImage } from "@utils/media";
|
||||
import { Choice } from "@utils/types";
|
||||
import autosize from "autosize";
|
||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
||||
import {
|
||||
|
@ -10,29 +24,18 @@ import {
|
|||
PostView,
|
||||
SearchResponse,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { PostFormParams } from "../../interfaces";
|
||||
import { UserService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
import {
|
||||
Choice,
|
||||
archiveTodayUrl,
|
||||
capitalizeFirstLetter,
|
||||
communityToChoice,
|
||||
fetchCommunities,
|
||||
getIdFromString,
|
||||
ghostArchiveUrl,
|
||||
isImage,
|
||||
myAuth,
|
||||
myAuthRequired,
|
||||
relTags,
|
||||
setupTippy,
|
||||
toast,
|
||||
trendingFetchLimit,
|
||||
validTitle,
|
||||
validURL,
|
||||
webArchiveUrl,
|
||||
} from "../../utils";
|
||||
} from "../../config";
|
||||
import { PostFormParams } from "../../interfaces";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { toast } from "../../toast";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { LanguageSelect } from "../common/language-select";
|
||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||
|
@ -338,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
|
||||
|
@ -356,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>
|
||||
|
@ -377,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(
|
||||
|
@ -386,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(
|
||||
|
@ -395,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>
|
||||
)}
|
||||
|
@ -407,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
|
||||
|
@ -451,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
|
||||
|
@ -468,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()}
|
||||
|
@ -476,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}
|
||||
|
@ -497,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
|
||||
|
@ -505,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,
|
||||
|
@ -526,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
|
||||
|
@ -549,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 && (
|
||||
|
@ -560,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>
|
||||
|
@ -586,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>
|
||||
)
|
||||
);
|
||||
|
@ -606,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
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { myAuthRequired, newVote, showScores } from "@utils/app";
|
||||
import { canShare, share } from "@utils/browser";
|
||||
import { futureDaysToUnixTime, hostname, numToSI } from "@utils/helpers";
|
||||
import { isImage, isVideo } from "@utils/media";
|
||||
import {
|
||||
amAdmin,
|
||||
amCommunityCreator,
|
||||
|
@ -34,25 +37,12 @@ import {
|
|||
SavePost,
|
||||
TransferCommunity,
|
||||
} 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 { UserService } from "../../services";
|
||||
import {
|
||||
futureDaysToUnixTime,
|
||||
hostname,
|
||||
isImage,
|
||||
isVideo,
|
||||
mdNoImages,
|
||||
mdToHtml,
|
||||
mdToHtmlInline,
|
||||
myAuthRequired,
|
||||
newVote,
|
||||
numToSI,
|
||||
relTags,
|
||||
setupTippy,
|
||||
showScores,
|
||||
} from "../../utils";
|
||||
import { mdNoImages, mdToHtml, mdToHtmlInline } from "../../markdown";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { Icon, PurgeWarning, Spinner } from "../common/icon";
|
||||
import { MomentTime } from "../common/moment-time";
|
||||
import { PictrsImage } from "../common/pictrs-image";
|
||||
|
@ -307,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" />
|
||||
|
@ -356,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" />
|
||||
|
@ -374,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>
|
||||
|
@ -421,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 ? (
|
||||
|
@ -447,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 ? (
|
||||
|
@ -472,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"
|
||||
|
@ -510,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
|
||||
|
@ -523,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>
|
||||
|
@ -537,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>
|
||||
|
@ -545,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>
|
||||
|
@ -554,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>
|
||||
|
@ -596,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}`}>
|
||||
|
@ -631,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 />
|
||||
|
@ -690,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>
|
||||
|
@ -734,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),
|
||||
});
|
||||
|
@ -746,11 +745,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
to={`/post/${post_view.post.id}?scrollToComments=true`}
|
||||
data-tippy-content={title}
|
||||
>
|
||||
<Icon icon="message-square" classes="me-1" inline />
|
||||
{post_view.counts.comments}
|
||||
<span className="me-1">
|
||||
<Icon icon="message-square" classes="me-1" inline />
|
||||
{post_view.counts.comments}
|
||||
</span>
|
||||
{this.unreadCount && (
|
||||
<span className="badge text-bg-warning">
|
||||
({this.unreadCount} {i18n.t("new")})
|
||||
<span className="text-muted fst-italic">
|
||||
({this.unreadCount} {I18NextService.i18n.t("new")})
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
|
@ -778,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 ? (
|
||||
|
@ -801,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 ? (
|
||||
|
@ -829,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"
|
||||
|
@ -862,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>
|
||||
|
@ -876,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>
|
||||
);
|
||||
}
|
||||
|
@ -889,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>
|
||||
);
|
||||
}
|
||||
|
@ -906,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"
|
||||
|
@ -944,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"
|
||||
|
@ -958,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"
|
||||
|
@ -984,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>
|
||||
|
@ -1011,7 +1018,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
})}
|
||||
inline
|
||||
/>
|
||||
{i18n.t("community")}
|
||||
{I18NextService.i18n.t("community")}
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
|
@ -1035,7 +1042,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
})}
|
||||
inline
|
||||
/>
|
||||
{i18n.t("local")}
|
||||
{I18NextService.i18n.t("local")}
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
|
@ -1059,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>
|
||||
);
|
||||
|
@ -1086,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
|
||||
|
@ -1097,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 && (
|
||||
|
@ -1108,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>
|
||||
)}
|
||||
|
@ -1134,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"
|
||||
|
@ -1159,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>
|
||||
</>
|
||||
))}
|
||||
|
@ -1174,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>
|
||||
</>
|
||||
)}
|
||||
|
@ -1213,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>
|
||||
)}
|
||||
|
@ -1237,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 && (
|
||||
|
@ -1250,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>
|
||||
)}
|
||||
|
@ -1276,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)}
|
||||
/>
|
||||
|
@ -1309,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>
|
||||
|
@ -1319,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>
|
||||
|
@ -1344,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)}
|
||||
|
@ -1358,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>
|
||||
)}
|
||||
|
@ -1371,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)}
|
||||
/>
|
||||
|
@ -1572,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;
|
||||
}
|
||||
|
||||
|
@ -1837,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),
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
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 { myAuthRequired } from "../../utils";
|
||||
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>
|
||||
|
|
|
@ -1,7 +1,29 @@
|
|||
import { isBrowser } from "@utils/browser";
|
||||
import {
|
||||
buildCommentsTree,
|
||||
commentsToFlatNodes,
|
||||
editComment,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
getCommentIdFromProps,
|
||||
getCommentParentId,
|
||||
getDepthFromComment,
|
||||
getIdFromProps,
|
||||
myAuth,
|
||||
setIsoData,
|
||||
updateCommunityBlock,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
import {
|
||||
isBrowser,
|
||||
restoreScrollPosition,
|
||||
saveScrollPosition,
|
||||
} from "@utils/browser";
|
||||
import { debounce } from "@utils/helpers";
|
||||
import { isImage } from "@utils/media";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import autosize from "autosize";
|
||||
import { Component, createRef, linkEvent, RefObject } from "inferno";
|
||||
import { Component, RefObject, createRef, linkEvent } from "inferno";
|
||||
import {
|
||||
AddAdmin,
|
||||
AddModToCommunity,
|
||||
|
@ -53,38 +75,16 @@ import {
|
|||
SavePost,
|
||||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { commentTreeMaxDepth } from "../../config";
|
||||
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 {
|
||||
buildCommentsTree,
|
||||
commentsToFlatNodes,
|
||||
commentTreeMaxDepth,
|
||||
editComment,
|
||||
editWith,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
getCommentIdFromProps,
|
||||
getCommentParentId,
|
||||
getDepthFromComment,
|
||||
getIdFromProps,
|
||||
isImage,
|
||||
myAuth,
|
||||
restoreScrollPosition,
|
||||
RouteDataResponse,
|
||||
saveScrollPosition,
|
||||
setIsoData,
|
||||
setupTippy,
|
||||
toast,
|
||||
updateCommunityBlock,
|
||||
updatePersonBlock,
|
||||
} from "../../utils";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { toast } from "../../toast";
|
||||
import { CommentForm } from "../comment/comment-form";
|
||||
import { CommentNodes } from "../comment/comment-nodes";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
|
@ -398,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
|
||||
|
@ -436,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"
|
||||
|
@ -450,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"
|
||||
|
@ -464,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"
|
||||
|
@ -478,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"
|
||||
|
@ -494,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"
|
||||
|
@ -593,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>
|
||||
)}
|
||||
</>
|
||||
|
@ -834,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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -980,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(`/`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { getRecipientIdFromProps, myAuth, setIsoData } from "@utils/app";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { Component } from "inferno";
|
||||
import {
|
||||
CreatePrivateMessage as CreatePrivateMessageI,
|
||||
|
@ -5,17 +7,10 @@ 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 {
|
||||
RouteDataResponse,
|
||||
getRecipientIdFromProps,
|
||||
myAuth,
|
||||
setIsoData,
|
||||
toast,
|
||||
} from "../../utils";
|
||||
import { toast } from "../../toast";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
import { PrivateMessageForm } from "./private-message-form";
|
||||
|
@ -101,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 "";
|
||||
}
|
||||
|
@ -120,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}
|
||||
|
@ -148,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("/");
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
import { capitalizeFirstLetter } from "@utils/helpers";
|
||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
||||
import { T } from "inferno-i18next-dess";
|
||||
import {
|
||||
|
@ -6,13 +8,9 @@ import {
|
|||
Person,
|
||||
PrivateMessageView,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import {
|
||||
capitalizeFirstLetter,
|
||||
myAuthRequired,
|
||||
relTags,
|
||||
setupTippy,
|
||||
} from "../../utils";
|
||||
import { relTags } from "../../config";
|
||||
import { I18NextService } from "../../services";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||
import NavigationPrompt from "../common/navigation-prompt";
|
||||
|
@ -68,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() {
|
||||
|
@ -85,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">
|
||||
|
@ -95,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>
|
||||
|
@ -144,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 && (
|
||||
|
@ -155,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">
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
||||
import { T } from "inferno-i18next-dess";
|
||||
import {
|
||||
PrivateMessageReportView,
|
||||
ResolvePrivateMessageReport,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { mdToHtml, myAuthRequired } from "../../utils";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { PersonListing } from "../person/person-listing";
|
||||
|
||||
|
@ -38,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>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { myAuthRequired } from "@utils/app";
|
||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
||||
import {
|
||||
CreatePrivateMessage,
|
||||
|
@ -8,9 +9,8 @@ import {
|
|||
Person,
|
||||
PrivateMessageView,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../../i18next";
|
||||
import { UserService } from "../../services";
|
||||
import { mdToHtml, myAuthRequired } from "../../utils";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { MomentTime } from "../common/moment-time";
|
||||
import { PersonListing } from "../person/person-listing";
|
||||
|
@ -93,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} />
|
||||
|
@ -147,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 ? (
|
||||
|
@ -174,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>
|
||||
|
@ -188,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>
|
||||
|
@ -200,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 ? (
|
||||
|
@ -228,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"
|
||||
|
@ -249,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)}
|
||||
|
@ -263,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>
|
||||
)}
|
||||
|
@ -286,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>
|
||||
|
@ -296,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) {
|
||||
|
|
|
@ -1,5 +1,28 @@
|
|||
import { debounce, getQueryParams, getQueryString } from "@utils/helpers";
|
||||
import {
|
||||
commentsToFlatNodes,
|
||||
communityToChoice,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
fetchCommunities,
|
||||
fetchUsers,
|
||||
getUpdatedSearchId,
|
||||
myAuth,
|
||||
personToChoice,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
} from "@utils/app";
|
||||
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
|
||||
import {
|
||||
capitalizeFirstLetter,
|
||||
debounce,
|
||||
getIdFromString,
|
||||
getPageFromString,
|
||||
getQueryParams,
|
||||
getQueryString,
|
||||
numToSI,
|
||||
} from "@utils/helpers";
|
||||
import type { QueryParams } from "@utils/types";
|
||||
import { Choice, RouteDataResponse } from "@utils/types";
|
||||
import type { NoOptionI18nKeys } from "i18next";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import {
|
||||
|
@ -22,32 +45,10 @@ import {
|
|||
SearchType,
|
||||
SortType,
|
||||
} from "lemmy-js-client";
|
||||
import { i18n } from "../i18next";
|
||||
import { fetchLimit } from "../config";
|
||||
import { CommentViewType, InitialFetchRequest } from "../interfaces";
|
||||
import { FirstLoadService } from "../services/FirstLoadService";
|
||||
import { FirstLoadService, I18NextService } from "../services";
|
||||
import { HttpService, RequestState } from "../services/HttpService";
|
||||
import {
|
||||
Choice,
|
||||
RouteDataResponse,
|
||||
capitalizeFirstLetter,
|
||||
commentsToFlatNodes,
|
||||
communityToChoice,
|
||||
enableDownvotes,
|
||||
enableNsfw,
|
||||
fetchCommunities,
|
||||
fetchLimit,
|
||||
fetchUsers,
|
||||
getIdFromString,
|
||||
getPageFromString,
|
||||
getUpdatedSearchId,
|
||||
myAuth,
|
||||
numToSI,
|
||||
personToChoice,
|
||||
restoreScrollPosition,
|
||||
saveScrollPosition,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
} from "../utils";
|
||||
import { CommentNodes } from "./comment/comment-nodes";
|
||||
import { HtmlTags } from "./common/html-tags";
|
||||
import { Spinner } from "./common/icon";
|
||||
|
@ -182,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)}
|
||||
|
@ -226,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>
|
||||
|
@ -446,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() {
|
||||
|
@ -458,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>
|
||||
|
@ -497,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}
|
||||
|
@ -509,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>
|
||||
|
@ -538,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>
|
||||
|
|
26
src/shared/config.ts
Normal file
26
src/shared/config.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
export const favIconUrl = "/static/assets/icons/favicon.svg";
|
||||
export const favIconPngUrl = "/static/assets/icons/apple-touch-icon.png";
|
||||
|
||||
export const repoUrl = "https://github.com/LemmyNet";
|
||||
export const joinLemmyUrl = "https://join-lemmy.org";
|
||||
export const donateLemmyUrl = `${joinLemmyUrl}/donate`;
|
||||
export const docsUrl = `${joinLemmyUrl}/docs/en/index.html`;
|
||||
export const helpGuideUrl = `${joinLemmyUrl}/docs/en/users/01-getting-started.html`; // TODO find a way to redirect to the non-en folder
|
||||
export const markdownHelpUrl = `${joinLemmyUrl}/docs/en/users/02-media.html`;
|
||||
export const sortingHelpUrl = `${joinLemmyUrl}/docs/en/users/03-votes-and-ranking.html`;
|
||||
export const archiveTodayUrl = "https://archive.today";
|
||||
export const ghostArchiveUrl = "https://ghostarchive.org";
|
||||
export const webArchiveUrl = "https://web.archive.org";
|
||||
export const elementUrl = "https://element.io";
|
||||
|
||||
export const postRefetchSeconds: number = 60 * 1000;
|
||||
export const trendingFetchLimit = 6;
|
||||
export const mentionDropdownFetchLimit = 10;
|
||||
export const commentTreeMaxDepth = 8;
|
||||
export const markdownFieldCharacterLimit = 50000;
|
||||
export const maxUploadImages = 20;
|
||||
export const concurrentImageUpload = 4;
|
||||
export const updateUnreadCountsInterval = 30000;
|
||||
export const fetchLimit = 40;
|
||||
export const relTags = "noopener nofollow";
|
||||
export const emDash = "\u2014";
|
|
@ -1,7 +1,7 @@
|
|||
import { ErrorPageData } from "@utils/types";
|
||||
import { CommentView, GetSiteResponse } from "lemmy-js-client";
|
||||
import type { ParsedQs } from "qs";
|
||||
import { RequestState, WrappedLemmyHttp } from "./services/HttpService";
|
||||
import { ErrorPageData } from "./utils";
|
||||
|
||||
/**
|
||||
* This contains serialized data, it needs to be deserialized before use.
|
||||
|
|
307
src/shared/markdown.ts
Normal file
307
src/shared/markdown.ts
Normal file
|
@ -0,0 +1,307 @@
|
|||
import { communitySearch, personSearch } from "@utils/app";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
import { debounce, groupBy } from "@utils/helpers";
|
||||
import { CommunityTribute, PersonTribute } from "@utils/types";
|
||||
import { Picker } from "emoji-mart";
|
||||
import emojiShortName from "emoji-short-name";
|
||||
import { CustomEmojiView } from "lemmy-js-client";
|
||||
import { default as MarkdownIt } from "markdown-it";
|
||||
import markdown_it_container from "markdown-it-container";
|
||||
// import markdown_it_emoji from "markdown-it-emoji/bare";
|
||||
import markdown_it_footnote from "markdown-it-footnote";
|
||||
import markdown_it_html5_embed from "markdown-it-html5-embed";
|
||||
import markdown_it_sub from "markdown-it-sub";
|
||||
import markdown_it_sup from "markdown-it-sup";
|
||||
import Renderer from "markdown-it/lib/renderer";
|
||||
import Token from "markdown-it/lib/token";
|
||||
|
||||
export let Tribute: any;
|
||||
|
||||
export let md: MarkdownIt = new MarkdownIt();
|
||||
|
||||
export let mdNoImages: MarkdownIt = new MarkdownIt();
|
||||
|
||||
export const customEmojis: EmojiMartCategory[] = [];
|
||||
|
||||
export let customEmojisLookup: Map<string, CustomEmojiView> = new Map<
|
||||
string,
|
||||
CustomEmojiView
|
||||
>();
|
||||
|
||||
if (isBrowser()) {
|
||||
Tribute = require("tributejs");
|
||||
}
|
||||
|
||||
export function mdToHtml(text: string) {
|
||||
return { __html: md.render(text) };
|
||||
}
|
||||
|
||||
export function mdToHtmlNoImages(text: string) {
|
||||
return { __html: mdNoImages.render(text) };
|
||||
}
|
||||
|
||||
export function mdToHtmlInline(text: string) {
|
||||
return { __html: md.renderInline(text) };
|
||||
}
|
||||
|
||||
const spoilerConfig = {
|
||||
validate: (params: string) => {
|
||||
return params.trim().match(/^spoiler\s+(.*)$/);
|
||||
},
|
||||
|
||||
render: (tokens: any, idx: any) => {
|
||||
var m = tokens[idx].info.trim().match(/^spoiler\s+(.*)$/);
|
||||
|
||||
if (tokens[idx].nesting === 1) {
|
||||
// opening tag
|
||||
return `<details><summary> ${md.utils.escapeHtml(m[1])} </summary>\n`;
|
||||
} else {
|
||||
// closing tag
|
||||
return "</details>\n";
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const html5EmbedConfig = {
|
||||
html5embed: {
|
||||
useImageSyntax: true, // Enables video/audio embed with ![]() syntax (default)
|
||||
attributes: {
|
||||
audio: 'controls preload="metadata"',
|
||||
video: 'width="100%" max-height="100%" controls loop preload="metadata"',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export function setupMarkdown() {
|
||||
const markdownItConfig: MarkdownIt.Options = {
|
||||
html: false,
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
};
|
||||
|
||||
// const emojiDefs = Array.from(customEmojisLookup.entries()).reduce(
|
||||
// (main, [key, value]) => ({ ...main, [key]: value }),
|
||||
// {}
|
||||
// );
|
||||
md = new MarkdownIt(markdownItConfig)
|
||||
.use(markdown_it_sub)
|
||||
.use(markdown_it_sup)
|
||||
.use(markdown_it_footnote)
|
||||
.use(markdown_it_html5_embed, html5EmbedConfig)
|
||||
.use(markdown_it_container, "spoiler", spoilerConfig);
|
||||
// .use(markdown_it_emoji, {
|
||||
// defs: emojiDefs,
|
||||
// });
|
||||
|
||||
mdNoImages = new MarkdownIt(markdownItConfig)
|
||||
.use(markdown_it_sub)
|
||||
.use(markdown_it_sup)
|
||||
.use(markdown_it_footnote)
|
||||
.use(markdown_it_html5_embed, html5EmbedConfig)
|
||||
.use(markdown_it_container, "spoiler", spoilerConfig)
|
||||
// .use(markdown_it_emoji, {
|
||||
// defs: emojiDefs,
|
||||
// })
|
||||
.disable("image");
|
||||
const defaultRenderer = md.renderer.rules.image;
|
||||
md.renderer.rules.image = function (
|
||||
tokens: Token[],
|
||||
idx: number,
|
||||
options: MarkdownIt.Options,
|
||||
env: any,
|
||||
self: Renderer
|
||||
) {
|
||||
//Provide custom renderer for our emojis to allow us to add a css class and force size dimensions on them.
|
||||
const item = tokens[idx] as any;
|
||||
const title = item.attrs.length >= 3 ? item.attrs[2][1] : "";
|
||||
const src: string = item.attrs[0][1];
|
||||
const isCustomEmoji = customEmojisLookup.get(title) != undefined;
|
||||
if (!isCustomEmoji) {
|
||||
return defaultRenderer?.(tokens, idx, options, env, self) ?? "";
|
||||
}
|
||||
const alt_text = item.content;
|
||||
return `<img class="icon icon-emoji" src="${src}" title="${title}" alt="${alt_text}"/>`;
|
||||
};
|
||||
md.renderer.rules.table_open = function () {
|
||||
return '<table class="table">';
|
||||
};
|
||||
}
|
||||
|
||||
export function setupEmojiDataModel(custom_emoji_views: CustomEmojiView[]) {
|
||||
const groupedEmojis = groupBy(
|
||||
custom_emoji_views,
|
||||
x => x.custom_emoji.category
|
||||
);
|
||||
for (const [category, emojis] of Object.entries(groupedEmojis)) {
|
||||
customEmojis.push({
|
||||
id: category,
|
||||
name: category,
|
||||
emojis: emojis.map(emoji => ({
|
||||
id: emoji.custom_emoji.shortcode,
|
||||
name: emoji.custom_emoji.shortcode,
|
||||
keywords: emoji.keywords.map(x => x.keyword),
|
||||
skins: [{ src: emoji.custom_emoji.image_url }],
|
||||
})),
|
||||
});
|
||||
}
|
||||
customEmojisLookup = new Map(
|
||||
custom_emoji_views.map(view => [view.custom_emoji.shortcode, view])
|
||||
);
|
||||
}
|
||||
|
||||
export function updateEmojiDataModel(custom_emoji_view: CustomEmojiView) {
|
||||
const emoji: EmojiMartCustomEmoji = {
|
||||
id: custom_emoji_view.custom_emoji.shortcode,
|
||||
name: custom_emoji_view.custom_emoji.shortcode,
|
||||
keywords: custom_emoji_view.keywords.map(x => x.keyword),
|
||||
skins: [{ src: custom_emoji_view.custom_emoji.image_url }],
|
||||
};
|
||||
const categoryIndex = customEmojis.findIndex(
|
||||
x => x.id == custom_emoji_view.custom_emoji.category
|
||||
);
|
||||
if (categoryIndex == -1) {
|
||||
customEmojis.push({
|
||||
id: custom_emoji_view.custom_emoji.category,
|
||||
name: custom_emoji_view.custom_emoji.category,
|
||||
emojis: [emoji],
|
||||
});
|
||||
} else {
|
||||
const emojiIndex = customEmojis[categoryIndex].emojis.findIndex(
|
||||
x => x.id == custom_emoji_view.custom_emoji.shortcode
|
||||
);
|
||||
if (emojiIndex == -1) {
|
||||
customEmojis[categoryIndex].emojis.push(emoji);
|
||||
} else {
|
||||
customEmojis[categoryIndex].emojis[emojiIndex] = emoji;
|
||||
}
|
||||
}
|
||||
customEmojisLookup.set(
|
||||
custom_emoji_view.custom_emoji.shortcode,
|
||||
custom_emoji_view
|
||||
);
|
||||
}
|
||||
|
||||
export function removeFromEmojiDataModel(id: number) {
|
||||
let view: CustomEmojiView | undefined;
|
||||
for (const item of customEmojisLookup.values()) {
|
||||
if (item.custom_emoji.id === id) {
|
||||
view = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!view) return;
|
||||
const categoryIndex = customEmojis.findIndex(
|
||||
x => x.id == view?.custom_emoji.category
|
||||
);
|
||||
const emojiIndex = customEmojis[categoryIndex].emojis.findIndex(
|
||||
x => x.id == view?.custom_emoji.shortcode
|
||||
);
|
||||
customEmojis[categoryIndex].emojis = customEmojis[
|
||||
categoryIndex
|
||||
].emojis.splice(emojiIndex, 1);
|
||||
|
||||
customEmojisLookup.delete(view?.custom_emoji.shortcode);
|
||||
}
|
||||
|
||||
export function getEmojiMart(
|
||||
onEmojiSelect: (e: any) => void,
|
||||
customPickerOptions: any = {}
|
||||
) {
|
||||
const pickerOptions = {
|
||||
...customPickerOptions,
|
||||
onEmojiSelect: onEmojiSelect,
|
||||
custom: customEmojis,
|
||||
};
|
||||
return new Picker(pickerOptions);
|
||||
}
|
||||
|
||||
export function setupTribute() {
|
||||
return new Tribute({
|
||||
noMatchTemplate: function () {
|
||||
return "";
|
||||
},
|
||||
collection: [
|
||||
// Emojis
|
||||
{
|
||||
trigger: ":",
|
||||
menuItemTemplate: (item: any) => {
|
||||
const shortName = `:${item.original.key}:`;
|
||||
return `${item.original.val} ${shortName}`;
|
||||
},
|
||||
selectTemplate: (item: any) => {
|
||||
const customEmoji = customEmojisLookup.get(
|
||||
item.original.key
|
||||
)?.custom_emoji;
|
||||
if (customEmoji == undefined) return `${item.original.val}`;
|
||||
else
|
||||
return `![${customEmoji.alt_text}](${customEmoji.image_url} "${customEmoji.shortcode}")`;
|
||||
},
|
||||
values: Object.entries(emojiShortName)
|
||||
.map(e => {
|
||||
return { key: e[1], val: e[0] };
|
||||
})
|
||||
.concat(
|
||||
Array.from(customEmojisLookup.entries()).map(k => ({
|
||||
key: k[0],
|
||||
val: `<img class="icon icon-emoji" src="${k[1].custom_emoji.image_url}" title="${k[1].custom_emoji.shortcode}" alt="${k[1].custom_emoji.alt_text}" />`,
|
||||
}))
|
||||
),
|
||||
allowSpaces: false,
|
||||
autocompleteMode: true,
|
||||
// TODO
|
||||
// menuItemLimit: mentionDropdownFetchLimit,
|
||||
menuShowMinLength: 2,
|
||||
},
|
||||
// Persons
|
||||
{
|
||||
trigger: "@",
|
||||
selectTemplate: (item: any) => {
|
||||
const it: PersonTribute = item.original;
|
||||
return `[${it.key}](${it.view.person.actor_id})`;
|
||||
},
|
||||
values: debounce(async (text: string, cb: any) => {
|
||||
cb(await personSearch(text));
|
||||
}),
|
||||
allowSpaces: false,
|
||||
autocompleteMode: true,
|
||||
// TODO
|
||||
// menuItemLimit: mentionDropdownFetchLimit,
|
||||
menuShowMinLength: 2,
|
||||
},
|
||||
|
||||
// Communities
|
||||
{
|
||||
trigger: "!",
|
||||
selectTemplate: (item: any) => {
|
||||
const it: CommunityTribute = item.original;
|
||||
return `[${it.key}](${it.view.community.actor_id})`;
|
||||
},
|
||||
values: debounce(async (text: string, cb: any) => {
|
||||
cb(await communitySearch(text));
|
||||
}),
|
||||
allowSpaces: false,
|
||||
autocompleteMode: true,
|
||||
// TODO
|
||||
// menuItemLimit: mentionDropdownFetchLimit,
|
||||
menuShowMinLength: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
interface EmojiMartCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
emojis: EmojiMartCustomEmoji[];
|
||||
}
|
||||
|
||||
interface EmojiMartCustomEmoji {
|
||||
id: string;
|
||||
name: string;
|
||||
keywords: string[];
|
||||
skins: EmojiMartSkin[];
|
||||
}
|
||||
|
||||
interface EmojiMartSkin {
|
||||
src: string;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import { LemmyHttp } from "lemmy-js-client";
|
||||
import { getHttpBase } from "../../shared/env";
|
||||
import { i18n } from "../../shared/i18next";
|
||||
import { toast } from "../../shared/utils";
|
||||
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,
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
import { isBrowser } from "@utils/browser";
|
||||
import i18next, { i18nTyped, 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";
|
||||
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,16 +92,30 @@ class LanguageDetector {
|
|||
}
|
||||
}
|
||||
|
||||
i18next.use(LanguageDetector).init({
|
||||
debug: false,
|
||||
compatibilityJSON: "v3",
|
||||
supportedLngs: languages.map(l => l.code),
|
||||
nonExplicitSupportedLngs: true,
|
||||
// load: 'languageOnly',
|
||||
// initImmediate: false,
|
||||
fallbackLng: "en",
|
||||
resources,
|
||||
interpolation: { format },
|
||||
});
|
||||
export class I18NextService {
|
||||
#i18n: typeof i18next;
|
||||
static #instance: I18NextService;
|
||||
|
||||
export const i18n = i18next as i18nTyped;
|
||||
private constructor() {
|
||||
this.#i18n = i18next;
|
||||
this.#i18n.use(LanguageDetector).init({
|
||||
debug: false,
|
||||
compatibilityJSON: "v3",
|
||||
supportedLngs: languages.map(l => l.code),
|
||||
nonExplicitSupportedLngs: true,
|
||||
// load: 'languageOnly',
|
||||
// initImmediate: false,
|
||||
fallbackLng: "en",
|
||||
resources,
|
||||
interpolation: { format },
|
||||
});
|
||||
}
|
||||
|
||||
static get #Instance() {
|
||||
return this.#instance ?? (this.#instance = new this());
|
||||
}
|
||||
|
||||
public static get i18n() {
|
||||
return this.#Instance.#i18n;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
// import Cookies from 'js-cookie';
|
||||
import { isAuthPath } from "@utils/app";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
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 { isAuthPath, toast } from "../utils";
|
||||
import { toast } from "../toast";
|
||||
import { I18NextService } from "./I18NextService";
|
||||
|
||||
interface Claims {
|
||||
sub: number;
|
||||
|
@ -31,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();
|
||||
}
|
||||
|
@ -57,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;
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
export { FirstLoadService } from "./FirstLoadService";
|
||||
export { HistoryService } from "./HistoryService";
|
||||
export { HttpService } from "./HttpService";
|
||||
export { I18NextService } from "./I18NextService";
|
||||
export { UserService } from "./UserService";
|
||||
|
|
19
src/shared/tippy.ts
Normal file
19
src/shared/tippy.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { isBrowser } from "@utils/browser";
|
||||
import tippy from "tippy.js";
|
||||
|
||||
export let tippyInstance: any;
|
||||
|
||||
if (isBrowser()) {
|
||||
tippyInstance = tippy("[data-tippy-content]");
|
||||
}
|
||||
|
||||
export function setupTippy() {
|
||||
if (isBrowser()) {
|
||||
tippyInstance.forEach((e: any) => e.destroy());
|
||||
tippyInstance = tippy("[data-tippy-content]", {
|
||||
delay: [500, 0],
|
||||
// Display on "long press"
|
||||
touch: ["hold", 500],
|
||||
});
|
||||
}
|
||||
}
|
59
src/shared/toast.ts
Normal file
59
src/shared/toast.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { isBrowser } from "@utils/browser";
|
||||
import { ThemeColor } from "@utils/types";
|
||||
import Toastify from "toastify-js";
|
||||
import { I18NextService } from "./services";
|
||||
|
||||
export function toast(text: string, background: ThemeColor = "success") {
|
||||
if (isBrowser()) {
|
||||
const backgroundColor = `var(--bs-${background})`;
|
||||
Toastify({
|
||||
text: text,
|
||||
backgroundColor: backgroundColor,
|
||||
gravity: "bottom",
|
||||
position: "left",
|
||||
duration: 5000,
|
||||
}).showToast();
|
||||
}
|
||||
}
|
||||
|
||||
export function pictrsDeleteToast(filename: string, deleteUrl: string) {
|
||||
if (isBrowser()) {
|
||||
const clickToDeleteText = I18NextService.i18n.t("click_to_delete_picture", {
|
||||
filename,
|
||||
});
|
||||
const deletePictureText = I18NextService.i18n.t("picture_deleted", {
|
||||
filename,
|
||||
});
|
||||
const failedDeletePictureText = I18NextService.i18n.t(
|
||||
"failed_to_delete_picture",
|
||||
{
|
||||
filename,
|
||||
}
|
||||
);
|
||||
|
||||
const backgroundColor = `var(--bs-light)`;
|
||||
|
||||
const toast = Toastify({
|
||||
text: clickToDeleteText,
|
||||
backgroundColor: backgroundColor,
|
||||
gravity: "top",
|
||||
position: "right",
|
||||
duration: 10000,
|
||||
onClick: () => {
|
||||
if (toast) {
|
||||
fetch(deleteUrl).then(res => {
|
||||
toast.hideToast();
|
||||
if (res.ok === true) {
|
||||
alert(deletePictureText);
|
||||
} else {
|
||||
alert(failedDeletePictureText);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
close: true,
|
||||
});
|
||||
|
||||
toast.showToast();
|
||||
}
|
||||
}
|
1281
src/shared/utils.ts
1281
src/shared/utils.ts
File diff suppressed because it is too large
Load diff
54
src/shared/utils/app/build-comments-tree.ts
Normal file
54
src/shared/utils/app/build-comments-tree.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import { getCommentParentId, getDepthFromComment } from "@utils/app";
|
||||
import { CommentView } from "lemmy-js-client";
|
||||
import { CommentNodeI } from "../../interfaces";
|
||||
|
||||
export default function buildCommentsTree(
|
||||
comments: CommentView[],
|
||||
parentComment: boolean
|
||||
): CommentNodeI[] {
|
||||
const map = new Map<number, CommentNodeI>();
|
||||
const depthOffset = !parentComment
|
||||
? 0
|
||||
: getDepthFromComment(comments[0].comment) ?? 0;
|
||||
|
||||
for (const comment_view of comments) {
|
||||
const depthI = getDepthFromComment(comment_view.comment) ?? 0;
|
||||
const depth = depthI ? depthI - depthOffset : 0;
|
||||
const node: CommentNodeI = {
|
||||
comment_view,
|
||||
children: [],
|
||||
depth,
|
||||
};
|
||||
map.set(comment_view.comment.id, { ...node });
|
||||
}
|
||||
|
||||
const tree: CommentNodeI[] = [];
|
||||
|
||||
// if its a parent comment fetch, then push the first comment to the top node.
|
||||
if (parentComment) {
|
||||
const cNode = map.get(comments[0].comment.id);
|
||||
if (cNode) {
|
||||
tree.push(cNode);
|
||||
}
|
||||
}
|
||||
|
||||
for (const comment_view of comments) {
|
||||
const child = map.get(comment_view.comment.id);
|
||||
if (child) {
|
||||
const parent_id = getCommentParentId(comment_view.comment);
|
||||
if (parent_id) {
|
||||
const parent = map.get(parent_id);
|
||||
// Necessary because blocked comment might not exist
|
||||
if (parent) {
|
||||
parent.children.push(child);
|
||||
}
|
||||
} else {
|
||||
if (!parentComment) {
|
||||
tree.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
11
src/shared/utils/app/color-list.ts
Normal file
11
src/shared/utils/app/color-list.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { hsl } from "@utils/helpers";
|
||||
|
||||
export const colorList: string[] = [
|
||||
hsl(0),
|
||||
hsl(50),
|
||||
hsl(100),
|
||||
hsl(150),
|
||||
hsl(200),
|
||||
hsl(250),
|
||||
hsl(300),
|
||||
];
|
12
src/shared/utils/app/comments-to-flat-nodes.ts
Normal file
12
src/shared/utils/app/comments-to-flat-nodes.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { CommentView } from "lemmy-js-client";
|
||||
import { CommentNodeI } from "../../interfaces";
|
||||
|
||||
export default function commentsToFlatNodes(
|
||||
comments: CommentView[]
|
||||
): CommentNodeI[] {
|
||||
const nodes: CommentNodeI[] = [];
|
||||
for (const comment of comments) {
|
||||
nodes.push({ comment_view: comment, children: [], depth: 0 });
|
||||
}
|
||||
return nodes;
|
||||
}
|
4
src/shared/utils/app/community-rss-url.ts
Normal file
4
src/shared/utils/app/community-rss-url.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export default function communityRSSUrl(actorId: string, sort: string): string {
|
||||
const url = new URL(actorId);
|
||||
return `${url.origin}/feeds${url.pathname}.xml?sort=${sort}`;
|
||||
}
|
14
src/shared/utils/app/community-search.ts
Normal file
14
src/shared/utils/app/community-search.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { fetchCommunities } from "@utils/app";
|
||||
import { hostname } from "@utils/helpers";
|
||||
import { CommunityTribute } from "@utils/types";
|
||||
|
||||
export default async function communitySearch(
|
||||
text: string
|
||||
): Promise<CommunityTribute[]> {
|
||||
const communitiesResponse = await fetchCommunities(text);
|
||||
|
||||
return communitiesResponse.map(cv => ({
|
||||
key: `!${cv.community.name}@${hostname(cv.community.actor_id)}`,
|
||||
view: cv,
|
||||
}));
|
||||
}
|
8
src/shared/utils/app/community-select-name.ts
Normal file
8
src/shared/utils/app/community-select-name.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { hostname } from "@utils/helpers";
|
||||
import { CommunityView } from "lemmy-js-client";
|
||||
|
||||
export default function communitySelectName(cv: CommunityView): string {
|
||||
return cv.community.local
|
||||
? cv.community.title
|
||||
: `${hostname(cv.community.actor_id)}/${cv.community.title}`;
|
||||
}
|
10
src/shared/utils/app/community-to-choice.ts
Normal file
10
src/shared/utils/app/community-to-choice.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { communitySelectName } from "@utils/app";
|
||||
import { Choice } from "@utils/types";
|
||||
import { CommunityView } from "lemmy-js-client";
|
||||
|
||||
export default function communityToChoice(cv: CommunityView): Choice {
|
||||
return {
|
||||
value: cv.community.id.toString(),
|
||||
label: communitySelectName(cv),
|
||||
};
|
||||
}
|
25
src/shared/utils/app/convert-comment-sort-type.ts
Normal file
25
src/shared/utils/app/convert-comment-sort-type.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { CommentSortType, SortType } from "lemmy-js-client";
|
||||
|
||||
export default function convertCommentSortType(
|
||||
sort: SortType
|
||||
): CommentSortType {
|
||||
switch (sort) {
|
||||
case "TopAll":
|
||||
case "TopDay":
|
||||
case "TopWeek":
|
||||
case "TopMonth":
|
||||
case "TopYear": {
|
||||
return "Top";
|
||||
}
|
||||
case "New": {
|
||||
return "New";
|
||||
}
|
||||
case "Hot":
|
||||
case "Active": {
|
||||
return "Hot";
|
||||
}
|
||||
default: {
|
||||
return "Hot";
|
||||
}
|
||||
}
|
||||
}
|
9
src/shared/utils/app/edit-comment-reply.ts
Normal file
9
src/shared/utils/app/edit-comment-reply.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { editListImmutable } from "@utils/helpers";
|
||||
import { CommentReplyView } from "lemmy-js-client";
|
||||
|
||||
export default function editCommentReply(
|
||||
data: CommentReplyView,
|
||||
replies: CommentReplyView[]
|
||||
): CommentReplyView[] {
|
||||
return editListImmutable("comment_reply", data, replies);
|
||||
}
|
9
src/shared/utils/app/edit-comment-report.ts
Normal file
9
src/shared/utils/app/edit-comment-report.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { editListImmutable } from "@utils/helpers";
|
||||
import { CommentReportView } from "lemmy-js-client";
|
||||
|
||||
export default function editCommentReport(
|
||||
data: CommentReportView,
|
||||
reports: CommentReportView[]
|
||||
): CommentReportView[] {
|
||||
return editListImmutable("comment_report", data, reports);
|
||||
}
|
9
src/shared/utils/app/edit-comment.ts
Normal file
9
src/shared/utils/app/edit-comment.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { editListImmutable } from "@utils/helpers";
|
||||
import { CommentView } from "lemmy-js-client";
|
||||
|
||||
export default function editComment(
|
||||
data: CommentView,
|
||||
comments: CommentView[]
|
||||
): CommentView[] {
|
||||
return editListImmutable("comment", data, comments);
|
||||
}
|
9
src/shared/utils/app/edit-community.ts
Normal file
9
src/shared/utils/app/edit-community.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { editListImmutable } from "@utils/helpers";
|
||||
import { CommunityView } from "lemmy-js-client";
|
||||
|
||||
export default function editCommunity(
|
||||
data: CommunityView,
|
||||
communities: CommunityView[]
|
||||
): CommunityView[] {
|
||||
return editListImmutable("community", data, communities);
|
||||
}
|
9
src/shared/utils/app/edit-mention.ts
Normal file
9
src/shared/utils/app/edit-mention.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { editListImmutable } from "@utils/helpers";
|
||||
import { PersonMentionView } from "lemmy-js-client";
|
||||
|
||||
export default function editMention(
|
||||
data: PersonMentionView,
|
||||
comments: PersonMentionView[]
|
||||
): PersonMentionView[] {
|
||||
return editListImmutable("person_mention", data, comments);
|
||||
}
|
9
src/shared/utils/app/edit-post-report.ts
Normal file
9
src/shared/utils/app/edit-post-report.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { editListImmutable } from "@utils/helpers";
|
||||
import { PostReportView } from "lemmy-js-client";
|
||||
|
||||
export default function editPostReport(
|
||||
data: PostReportView,
|
||||
reports: PostReportView[]
|
||||
) {
|
||||
return editListImmutable("post_report", data, reports);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue