mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f699d9675 | ||
|
|
a5aba6f7ae | ||
|
|
78c8711a79 | ||
|
|
8325236d0e | ||
|
|
437401e73f | ||
|
|
fa06d321d5 | ||
|
|
d1ddcb6ace | ||
|
|
6944d4dc0b | ||
|
|
c835d805b1 | ||
|
|
4a90e1f69d | ||
|
|
fcfeaa462e | ||
|
|
b16978d8fe | ||
|
|
68c62b4528 | ||
|
|
18f68aab31 | ||
|
|
8abb2770ec | ||
|
|
9156b8b6d0 | ||
|
|
2c32fa1e13 | ||
|
|
7e48afe36c | ||
|
|
cd94a3b56f | ||
|
|
22e0f1f382 |
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,5 +1,17 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [3.7.0]
|
||||||
|
|
||||||
|
- the sidebar is now resizable
|
||||||
|
- added the "f" keyboard shortcut to hide the sidebar
|
||||||
|
- added tooltips to relative dates with the exact date
|
||||||
|
- add a setting to hide commafeed from search engines (exposes a robots.txt file, enabled by default)
|
||||||
|
- the browser extension unread count now updates when articles are marked as read/unread in the app
|
||||||
|
- The "b" keyboard shortcut now works as expected on Chrome but requires the browser extension to be installed
|
||||||
|
- dark mode has been disabled on the api documentation page as it was unreadable
|
||||||
|
- improvement to the feed refresh queuing logic when "heavy load" mode is enabled
|
||||||
|
- fix a bug that could prevent feeds and categories from being edited
|
||||||
|
|
||||||
## [3.6.0]
|
## [3.6.0]
|
||||||
|
|
||||||
- add a button to open CommaFeed in a new tab and a button to open options when using the browser extension
|
- add a button to open CommaFeed in a new tab and a button to open options when using the browser extension
|
||||||
@@ -26,7 +38,8 @@
|
|||||||
- add divider to visually separate read-only information from form on the profile settings page
|
- add divider to visually separate read-only information from form on the profile settings page
|
||||||
- reduce javascript bundle size by 30% by loading only the necessary translations
|
- reduce javascript bundle size by 30% by loading only the necessary translations
|
||||||
- add a standalone donate page with all ways to support CommaFeed
|
- add a standalone donate page with all ways to support CommaFeed
|
||||||
- fix an issue introduced in 3.1.0 that could make CommaFeed not refresh feeds as fast as before on instances with lots of feeds
|
- fix an issue introduced in 3.1.0 that could make CommaFeed not refresh feeds as fast as before on instances with lots
|
||||||
|
of feeds
|
||||||
- fix alignment of icon with text for category tree nodes
|
- fix alignment of icon with text for category tree nodes
|
||||||
- fix alignment of burger button with the rest of the header on mobile
|
- fix alignment of burger button with the rest of the header on mobile
|
||||||
|
|
||||||
@@ -67,10 +80,10 @@
|
|||||||
## [3.0.1]
|
## [3.0.1]
|
||||||
|
|
||||||
- allow env variable substitution in config.yml
|
- allow env variable substitution in config.yml
|
||||||
- e.g. having a custom config.yml file with `app.session.path=${SOME_ENV_VAR}` will substitute `SOME_ENV_VAR` with
|
- e.g. having a custom config.yml file with `app.session.path=${SOME_ENV_VAR}` will substitute `SOME_ENV_VAR` with
|
||||||
its value
|
its value
|
||||||
- allow env variable prefixed with `CF_` to override config.yml properties
|
- allow env variable prefixed with `CF_` to override config.yml properties
|
||||||
- e.g. setting `CF_APP_ALLOWREGISTRATIONS=true` will set `app.allowRegistrations` to `true`
|
- e.g. setting `CF_APP_ALLOWREGISTRATIONS=true` will set `app.allowRegistrations` to `true`
|
||||||
|
|
||||||
## [3.0.0]
|
## [3.0.0]
|
||||||
|
|
||||||
|
|||||||
10
commafeed-client/package-lock.json
generated
10
commafeed-client/package-lock.json
generated
@@ -25,6 +25,7 @@
|
|||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"interweave": "^13.1.0",
|
"interweave": "^13.1.0",
|
||||||
"mousetrap": "^1.6.5",
|
"mousetrap": "^1.6.5",
|
||||||
|
"re-resizable": "^6.9.9",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-async-hook": "^4.0.0",
|
"react-async-hook": "^4.0.0",
|
||||||
"react-contexify": "^6.0.0",
|
"react-contexify": "^6.0.0",
|
||||||
@@ -10035,6 +10036,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/re-resizable": {
|
||||||
|
"version": "6.9.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.9.9.tgz",
|
||||||
|
"integrity": "sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react": {
|
"node_modules/react": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"interweave": "^13.1.0",
|
"interweave": "^13.1.0",
|
||||||
"mousetrap": "^1.6.5",
|
"mousetrap": "^1.6.5",
|
||||||
|
"re-resizable": "^6.9.9",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-async-hook": "^4.0.0",
|
"react-async-hook": "^4.0.0",
|
||||||
"react-contexify": "^6.0.0",
|
"react-contexify": "^6.0.0",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed</artifactId>
|
<artifactId>commafeed</artifactId>
|
||||||
<version>3.6.0</version>
|
<version>3.7.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>commafeed-client</artifactId>
|
<artifactId>commafeed-client</artifactId>
|
||||||
<name>CommaFeed Client</name>
|
<name>CommaFeed Client</name>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { categoryUnreadCount } from "app/utils"
|
|||||||
import { ErrorBoundary } from "components/ErrorBoundary"
|
import { ErrorBoundary } from "components/ErrorBoundary"
|
||||||
import { Header } from "components/header/Header"
|
import { Header } from "components/header/Header"
|
||||||
import { Tree } from "components/sidebar/Tree"
|
import { Tree } from "components/sidebar/Tree"
|
||||||
|
import { useBrowserExtension } from "hooks/useBrowserExtension"
|
||||||
import { useI18n } from "i18n"
|
import { useI18n } from "i18n"
|
||||||
import { AdminUsersPage } from "pages/admin/AdminUsersPage"
|
import { AdminUsersPage } from "pages/admin/AdminUsersPage"
|
||||||
import { MetricsPage } from "pages/admin/MetricsPage"
|
import { MetricsPage } from "pages/admin/MetricsPage"
|
||||||
@@ -37,7 +38,7 @@ import useLocalStorage from "use-local-storage"
|
|||||||
function Providers(props: { children: React.ReactNode }) {
|
function Providers(props: { children: React.ReactNode }) {
|
||||||
const preferredColorScheme = useColorScheme()
|
const preferredColorScheme = useColorScheme()
|
||||||
const [colorScheme, setColorScheme] = useLocalStorage<ColorScheme>("color-scheme", preferredColorScheme)
|
const [colorScheme, setColorScheme] = useLocalStorage<ColorScheme>("color-scheme", preferredColorScheme)
|
||||||
const toggleColorScheme = (value?: ColorScheme) => setColorScheme(value || (colorScheme === "dark" ? "light" : "dark"))
|
const toggleColorScheme = (value?: ColorScheme) => setColorScheme(value ?? (colorScheme === "dark" ? "light" : "dark"))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<I18nProvider i18n={i18n}>
|
<I18nProvider i18n={i18n}>
|
||||||
@@ -65,6 +66,9 @@ function Providers(props: { children: React.ReactNode }) {
|
|||||||
const ApiDocumentationPage = React.lazy(() => import("pages/app/ApiDocumentationPage"))
|
const ApiDocumentationPage = React.lazy(() => import("pages/app/ApiDocumentationPage"))
|
||||||
|
|
||||||
function AppRoutes() {
|
function AppRoutes() {
|
||||||
|
const sidebarWidth = useAppSelector(state => state.tree.sidebarWidth)
|
||||||
|
const sidebarVisible = useAppSelector(state => state.tree.sidebarVisible)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Navigate to={`/app/category/${Constants.categories.all.id}`} replace />} />
|
<Route path="/" element={<Navigate to={`/app/category/${Constants.categories.all.id}`} replace />} />
|
||||||
@@ -73,7 +77,7 @@ function AppRoutes() {
|
|||||||
<Route path="register" element={<RegistrationPage />} />
|
<Route path="register" element={<RegistrationPage />} />
|
||||||
<Route path="passwordRecovery" element={<PasswordRecoveryPage />} />
|
<Route path="passwordRecovery" element={<PasswordRecoveryPage />} />
|
||||||
<Route path="api" element={<ApiDocumentationPage />} />
|
<Route path="api" element={<ApiDocumentationPage />} />
|
||||||
<Route path="app" element={<Layout header={<Header />} sidebar={<Tree />} />}>
|
<Route path="app" element={<Layout header={<Header />} sidebar={<Tree />} sidebarWidth={sidebarVisible ? sidebarWidth : 0} />}>
|
||||||
<Route path="category">
|
<Route path="category">
|
||||||
<Route path=":id" element={<FeedEntriesPage sourceType="category" />} />
|
<Route path=":id" element={<FeedEntriesPage sourceType="category" />} />
|
||||||
<Route path=":id/details" element={<CategoryDetailsPage />} />
|
<Route path=":id/details" element={<CategoryDetailsPage />} />
|
||||||
@@ -134,13 +138,28 @@ function FaviconHandler() {
|
|||||||
const root = useAppSelector(state => state.tree.rootCategory)
|
const root = useAppSelector(state => state.tree.rootCategory)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unreadCount = categoryUnreadCount(root)
|
const unreadCount = categoryUnreadCount(root)
|
||||||
if (unreadCount === 0) Tinycon.reset()
|
if (unreadCount === 0) {
|
||||||
else Tinycon.setBubble(unreadCount)
|
Tinycon.reset()
|
||||||
|
} else {
|
||||||
|
Tinycon.setBubble(unreadCount)
|
||||||
|
}
|
||||||
}, [root])
|
}, [root])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function BrowserExtensionBadgeUnreadCountHandler() {
|
||||||
|
const root = useAppSelector(state => state.tree.rootCategory)
|
||||||
|
const { setBadgeUnreadCount } = useBrowserExtension()
|
||||||
|
useEffect(() => {
|
||||||
|
if (!root) return
|
||||||
|
const unreadCount = categoryUnreadCount(root)
|
||||||
|
setBadgeUnreadCount(unreadCount)
|
||||||
|
}, [root, setBadgeUnreadCount])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
useI18n()
|
useI18n()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
@@ -153,6 +172,7 @@ export function App() {
|
|||||||
<Providers>
|
<Providers>
|
||||||
<>
|
<>
|
||||||
<FaviconHandler />
|
<FaviconHandler />
|
||||||
|
<BrowserExtensionBadgeUnreadCountHandler />
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<GoogleAnalyticsHandler />
|
<GoogleAnalyticsHandler />
|
||||||
<RedirectHandler />
|
<RedirectHandler />
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ export const Constants = {
|
|||||||
layout: {
|
layout: {
|
||||||
mobileBreakpoint: DEFAULT_THEME.breakpoints.md,
|
mobileBreakpoint: DEFAULT_THEME.breakpoints.md,
|
||||||
headerHeight: 60,
|
headerHeight: 60,
|
||||||
sidebarWidth: 350,
|
|
||||||
entryMaxWidth: 650,
|
entryMaxWidth: 650,
|
||||||
isTopVisible: (div: HTMLElement) => div.getBoundingClientRect().top >= Constants.layout.headerHeight,
|
isTopVisible: (div: HTMLElement) => div.getBoundingClientRect().top >= Constants.layout.headerHeight,
|
||||||
isBottomVisible: (div: HTMLElement) => div.getBoundingClientRect().bottom <= window.innerHeight,
|
isBottomVisible: (div: HTMLElement) => div.getBoundingClientRect().bottom <= window.innerHeight,
|
||||||
@@ -97,5 +96,6 @@ export const Constants = {
|
|||||||
mainScrollAreaId: "main-scroll-area-id",
|
mainScrollAreaId: "main-scroll-area-id",
|
||||||
entryId: (entry: Entry) => `entry-id-${entry.id}`,
|
entryId: (entry: Entry) => `entry-id-${entry.id}`,
|
||||||
},
|
},
|
||||||
|
browserExtensionUrl: "https://github.com/Athou/commafeed-browser-extension",
|
||||||
bitcoinWalletAddress: "1dymfUxqCWpyD7a6rQSqNy4rLVDBsAr5e",
|
bitcoinWalletAddress: "1dymfUxqCWpyD7a6rQSqNy4rLVDBsAr5e",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,14 @@ import { redirectTo } from "./redirect"
|
|||||||
interface TreeState {
|
interface TreeState {
|
||||||
rootCategory?: Category
|
rootCategory?: Category
|
||||||
mobileMenuOpen: boolean
|
mobileMenuOpen: boolean
|
||||||
|
sidebarWidth: number
|
||||||
|
sidebarVisible: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: TreeState = {
|
const initialState: TreeState = {
|
||||||
mobileMenuOpen: false,
|
mobileMenuOpen: false,
|
||||||
|
sidebarWidth: 350,
|
||||||
|
sidebarVisible: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reloadTree = createAsyncThunk("tree/reload", () => client.category.getRoot().then(r => r.data))
|
export const reloadTree = createAsyncThunk("tree/reload", () => client.category.getRoot().then(r => r.data))
|
||||||
@@ -27,6 +31,12 @@ export const treeSlice = createSlice({
|
|||||||
setMobileMenuOpen: (state, action: PayloadAction<boolean>) => {
|
setMobileMenuOpen: (state, action: PayloadAction<boolean>) => {
|
||||||
state.mobileMenuOpen = action.payload
|
state.mobileMenuOpen = action.payload
|
||||||
},
|
},
|
||||||
|
setSidebarWidth: (state, action: PayloadAction<number>) => {
|
||||||
|
state.sidebarWidth = action.payload
|
||||||
|
},
|
||||||
|
toggleSidebar: state => {
|
||||||
|
state.sidebarVisible = !state.sidebarVisible
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers: builder => {
|
extraReducers: builder => {
|
||||||
builder.addCase(reloadTree.fulfilled, (state, action) => {
|
builder.addCase(reloadTree.fulfilled, (state, action) => {
|
||||||
@@ -54,5 +64,5 @@ export const treeSlice = createSlice({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const { setMobileMenuOpen } = treeSlice.actions
|
export const { setMobileMenuOpen, setSidebarWidth, toggleSidebar } = treeSlice.actions
|
||||||
export default treeSlice.reducer
|
export default treeSlice.reducer
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ export interface Subscription {
|
|||||||
iconUrl: string
|
iconUrl: string
|
||||||
unread: number
|
unread: number
|
||||||
categoryId?: string
|
categoryId?: string
|
||||||
position?: number
|
position: number
|
||||||
newestItemTime?: number
|
newestItemTime?: number
|
||||||
filter?: string
|
filter?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,17 +52,4 @@ export const scrollToWithCallback = ({
|
|||||||
element.scrollTo(options)
|
element.scrollTo(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const openLinkInBackgroundTab = (url: string) => {
|
|
||||||
// simulate ctrl+click to open tab in background
|
|
||||||
const a = document.createElement("a")
|
|
||||||
a.href = url
|
|
||||||
a.rel = "noreferrer"
|
|
||||||
a.dispatchEvent(
|
|
||||||
new MouseEvent("click", {
|
|
||||||
ctrlKey: true,
|
|
||||||
metaKey: true,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const truncate = (str: string, n: number) => (str.length > n ? `${str.slice(0, n - 1)}\u2026` : str)
|
export const truncate = (str: string, n: number) => (str.length > n ? `${str.slice(0, n - 1)}\u2026` : str)
|
||||||
|
|||||||
@@ -1,183 +1,200 @@
|
|||||||
import { Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Kbd, Table } from "@mantine/core"
|
import { Anchor, Box, Kbd, Stack, Table } from "@mantine/core"
|
||||||
|
import { Constants } from "app/constants"
|
||||||
|
|
||||||
export function KeyboardShortcutsHelp() {
|
export function KeyboardShortcutsHelp() {
|
||||||
return (
|
return (
|
||||||
<Table striped highlightOnHover>
|
<Stack spacing="xs">
|
||||||
<tbody>
|
<Table striped highlightOnHover>
|
||||||
<tr>
|
<tbody>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Refresh</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Refresh</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>R</Kbd>
|
<td>
|
||||||
</td>
|
<Kbd>R</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Open next entry</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Open next entry</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>J</Kbd>
|
<td>
|
||||||
</td>
|
<Kbd>J</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Open previous entry</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Open previous entry</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>K</Kbd>
|
<td>
|
||||||
</td>
|
<Kbd>K</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Set focus on next entry without opening it</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Set focus on next entry without opening it</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>N</Kbd>
|
<td>
|
||||||
</td>
|
<Kbd>N</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Set focus on previous entry without opening it</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Set focus on previous entry without opening it</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>P</Kbd>
|
<td>
|
||||||
</td>
|
<Kbd>P</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Move the page down</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Move the page down</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>
|
<td>
|
||||||
<Trans>Space</Trans>
|
<Kbd>
|
||||||
</Kbd>
|
<Trans>Space</Trans>
|
||||||
</td>
|
</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Move the page up</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Move the page up</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>
|
<td>
|
||||||
<Trans>Shift</Trans>
|
<Kbd>
|
||||||
</Kbd>
|
<Trans>Shift</Trans>
|
||||||
<span> + </span>
|
</Kbd>
|
||||||
<Kbd>
|
<span> + </span>
|
||||||
<Trans>Space</Trans>
|
<Kbd>
|
||||||
</Kbd>
|
<Trans>Space</Trans>
|
||||||
</td>
|
</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Open/close current entry</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Open/close current entry</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>O</Kbd>
|
<td>
|
||||||
<span>, </span>
|
<Kbd>O</Kbd>
|
||||||
<Kbd>
|
<span>, </span>
|
||||||
<Trans>Enter</Trans>
|
<Kbd>
|
||||||
</Kbd>
|
<Trans>Enter</Trans>
|
||||||
</td>
|
</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Open current entry in a new tab</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Open current entry in a new tab</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>V</Kbd>
|
<td>
|
||||||
</td>
|
<Kbd>V</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Open current entry in a new tab in the background</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Open current entry in a new tab in the background</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>B</Kbd>
|
<td>
|
||||||
<span>, </span>
|
<Kbd>B</Kbd>
|
||||||
<Kbd>
|
<span>*, </span>
|
||||||
<Trans>Middle click</Trans>
|
<Kbd>
|
||||||
</Kbd>
|
<Trans>Middle click</Trans>
|
||||||
</td>
|
</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Toggle read status of current entry</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Toggle read status of current entry</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>M</Kbd>
|
<td>
|
||||||
<span>, </span>
|
<Kbd>M</Kbd>
|
||||||
<Trans>Swipe header to the right</Trans>
|
<span>, </span>
|
||||||
</td>
|
<Trans>Swipe header to the right</Trans>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Mark all entries as read</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Mark all entries as read</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>
|
<td>
|
||||||
<Trans>Shift</Trans>
|
<Kbd>
|
||||||
</Kbd>
|
<Trans>Shift</Trans>
|
||||||
<span> + </span>
|
</Kbd>
|
||||||
<Kbd>A</Kbd>
|
<span> + </span>
|
||||||
</td>
|
<Kbd>A</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Go to the All view</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Go to the All view</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>G</Kbd>
|
<td>
|
||||||
<span> </span>
|
<Kbd>G</Kbd>
|
||||||
<Kbd>A</Kbd>
|
<span> </span>
|
||||||
</td>
|
<Kbd>A</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Navigate to a subscription by entering its name</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Navigate to a subscription by entering its name</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>
|
<td>
|
||||||
<Trans>Ctrl</Trans>
|
<Kbd>
|
||||||
</Kbd>
|
<Trans>Ctrl</Trans>
|
||||||
<span> + </span>
|
</Kbd>
|
||||||
<Kbd>K</Kbd>
|
<span> + </span>
|
||||||
<span>, </span>
|
<Kbd>K</Kbd>
|
||||||
<Kbd>G</Kbd>
|
<span>, </span>
|
||||||
<span> </span>
|
<Kbd>G</Kbd>
|
||||||
<Kbd>U</Kbd>
|
<span> </span>
|
||||||
</td>
|
<Kbd>U</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Show entry menu (desktop)</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Show entry menu (desktop)</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>
|
<td>
|
||||||
<Trans>Right click</Trans>
|
<Kbd>
|
||||||
</Kbd>
|
<Trans>Right click</Trans>
|
||||||
</td>
|
</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Show entry menu (mobile)</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Show entry menu (mobile)</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>
|
<td>
|
||||||
<Trans>Long press</Trans>
|
<Kbd>
|
||||||
</Kbd>
|
<Trans>Long press</Trans>
|
||||||
</td>
|
</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Trans>Show keyboard shortcut help</Trans>
|
<td>
|
||||||
</td>
|
<Trans>Toggle sidebar</Trans>
|
||||||
<td>
|
</td>
|
||||||
<Kbd>?</Kbd>
|
<td>
|
||||||
</td>
|
<Kbd>F</Kbd>
|
||||||
</tr>
|
</td>
|
||||||
</tbody>
|
</tr>
|
||||||
</Table>
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Trans>Show keyboard shortcut help</Trans>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<Kbd>?</Kbd>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
<Box>
|
||||||
|
<span>* </span>
|
||||||
|
<Anchor href={Constants.browserExtensionUrl} target="_blank" rel="noreferrer">
|
||||||
|
<Trans>Browser extension required for Chrome</Trans>
|
||||||
|
</Anchor>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
|
import { Tooltip } from "@mantine/core"
|
||||||
import dayjs from "dayjs"
|
import dayjs from "dayjs"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
@@ -10,5 +11,10 @@ export function RelativeDate(props: { date: Date | number | undefined }) {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
if (!props.date) return <Trans>N/A</Trans>
|
if (!props.date) return <Trans>N/A</Trans>
|
||||||
return <>{dayjs(props.date).from(dayjs(now))}</>
|
const date = dayjs(props.date)
|
||||||
|
return (
|
||||||
|
<Tooltip label={date.toString()} openDelay={500}>
|
||||||
|
<span>{date.from(dayjs(now))}</span>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ import {
|
|||||||
selectPreviousEntry,
|
selectPreviousEntry,
|
||||||
} from "app/slices/entries"
|
} from "app/slices/entries"
|
||||||
import { redirectToRootCategory } from "app/slices/redirect"
|
import { redirectToRootCategory } from "app/slices/redirect"
|
||||||
|
import { toggleSidebar } from "app/slices/tree"
|
||||||
import { useAppDispatch, useAppSelector } from "app/store"
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
import { openLinkInBackgroundTab } from "app/utils"
|
|
||||||
import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp"
|
import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp"
|
||||||
import { Loader } from "components/Loader"
|
import { Loader } from "components/Loader"
|
||||||
|
import { useBrowserExtension } from "hooks/useBrowserExtension"
|
||||||
import { useMousetrap } from "hooks/useMousetrap"
|
import { useMousetrap } from "hooks/useMousetrap"
|
||||||
import { useViewMode } from "hooks/useViewMode"
|
import { useViewMode } from "hooks/useViewMode"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
@@ -29,10 +30,12 @@ export function FeedEntries() {
|
|||||||
const entriesTimestamp = useAppSelector(state => state.entries.timestamp)
|
const entriesTimestamp = useAppSelector(state => state.entries.timestamp)
|
||||||
const selectedEntryId = useAppSelector(state => state.entries.selectedEntryId)
|
const selectedEntryId = useAppSelector(state => state.entries.selectedEntryId)
|
||||||
const hasMore = useAppSelector(state => state.entries.hasMore)
|
const hasMore = useAppSelector(state => state.entries.hasMore)
|
||||||
const { viewMode } = useViewMode()
|
|
||||||
const scrollMarks = useAppSelector(state => state.user.settings?.scrollMarks)
|
const scrollMarks = useAppSelector(state => state.user.settings?.scrollMarks)
|
||||||
const scrollingToEntry = useAppSelector(state => state.entries.scrollingToEntry)
|
const scrollingToEntry = useAppSelector(state => state.entries.scrollingToEntry)
|
||||||
|
const sidebarVisible = useAppSelector(state => state.tree.sidebarVisible)
|
||||||
|
const { viewMode } = useViewMode()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
const { openLinkInBackgroundTab } = useBrowserExtension()
|
||||||
|
|
||||||
const selectedEntry = entries.find(e => e.id === selectedEntryId)
|
const selectedEntry = entries.find(e => e.id === selectedEntryId)
|
||||||
|
|
||||||
@@ -211,7 +214,6 @@ export function FeedEntries() {
|
|||||||
window.open(selectedEntry.url, "_blank", "noreferrer")
|
window.open(selectedEntry.url, "_blank", "noreferrer")
|
||||||
})
|
})
|
||||||
useMousetrap("b", () => {
|
useMousetrap("b", () => {
|
||||||
// simulate ctrl+click to open tab in background
|
|
||||||
if (!selectedEntry) return
|
if (!selectedEntry) return
|
||||||
openLinkInBackgroundTab(selectedEntry.url)
|
openLinkInBackgroundTab(selectedEntry.url)
|
||||||
})
|
})
|
||||||
@@ -234,6 +236,7 @@ export function FeedEntries() {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
useMousetrap("g a", () => dispatch(redirectToRootCategory()))
|
useMousetrap("g a", () => dispatch(redirectToRootCategory()))
|
||||||
|
useMousetrap("f", () => dispatch(toggleSidebar()))
|
||||||
useMousetrap("?", () =>
|
useMousetrap("?", () =>
|
||||||
openModal({
|
openModal({
|
||||||
title: <Trans>Keyboard shortcuts</Trans>,
|
title: <Trans>Keyboard shortcuts</Trans>,
|
||||||
@@ -265,6 +268,7 @@ export function FeedEntries() {
|
|||||||
expanded={!!entry.expanded || viewMode === "expanded"}
|
expanded={!!entry.expanded || viewMode === "expanded"}
|
||||||
selected={entry.id === selectedEntryId}
|
selected={entry.id === selectedEntryId}
|
||||||
showSelectionIndicator={entry.id === selectedEntryId && (!entry.expanded || viewMode === "expanded")}
|
showSelectionIndicator={entry.id === selectedEntryId && (!entry.expanded || viewMode === "expanded")}
|
||||||
|
maxWidth={sidebarVisible ? Constants.layout.entryMaxWidth : undefined}
|
||||||
onHeaderClick={event => headerClicked(entry, event)}
|
onHeaderClick={event => headerClicked(entry, event)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,21 +18,31 @@ interface FeedEntryProps {
|
|||||||
expanded: boolean
|
expanded: boolean
|
||||||
selected: boolean
|
selected: boolean
|
||||||
showSelectionIndicator: boolean
|
showSelectionIndicator: boolean
|
||||||
|
maxWidth?: number
|
||||||
onHeaderClick: (e: React.MouseEvent) => void
|
onHeaderClick: (e: React.MouseEvent) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = createStyles((theme, props: FeedEntryProps & { viewMode?: ViewMode }) => {
|
const useStyles = createStyles((theme, props: FeedEntryProps & { viewMode?: ViewMode }) => {
|
||||||
let backgroundColor
|
let backgroundColor
|
||||||
if (theme.colorScheme === "dark") backgroundColor = props.entry.read ? "inherit" : theme.colors.dark[5]
|
if (theme.colorScheme === "dark") {
|
||||||
else backgroundColor = props.entry.read && !props.expanded ? theme.colors.gray[0] : "inherit"
|
backgroundColor = props.entry.read ? "inherit" : theme.colors.dark[5]
|
||||||
|
} else {
|
||||||
|
backgroundColor = props.entry.read && !props.expanded ? theme.colors.gray[0] : "inherit"
|
||||||
|
}
|
||||||
|
|
||||||
let marginY = 10
|
let marginY = 10
|
||||||
if (props.viewMode === "title") marginY = 2
|
if (props.viewMode === "title") {
|
||||||
else if (props.viewMode === "cozy") marginY = 6
|
marginY = 2
|
||||||
|
} else if (props.viewMode === "cozy") {
|
||||||
|
marginY = 6
|
||||||
|
}
|
||||||
|
|
||||||
let mobileMarginY = 6
|
let mobileMarginY = 6
|
||||||
if (props.viewMode === "title") mobileMarginY = 2
|
if (props.viewMode === "title") {
|
||||||
else if (props.viewMode === "cozy") mobileMarginY = 4
|
mobileMarginY = 2
|
||||||
|
} else if (props.viewMode === "cozy") {
|
||||||
|
mobileMarginY = 4
|
||||||
|
}
|
||||||
|
|
||||||
let backgroundHoverColor = backgroundColor
|
let backgroundHoverColor = backgroundColor
|
||||||
if (!props.expanded && !props.entry.read) {
|
if (!props.expanded && !props.entry.read) {
|
||||||
@@ -59,7 +69,7 @@ const useStyles = createStyles((theme, props: FeedEntryProps & { viewMode?: View
|
|||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
},
|
},
|
||||||
body: {
|
body: {
|
||||||
maxWidth: Constants.layout.entryMaxWidth,
|
maxWidth: props.maxWidth ?? "100%",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,12 +97,18 @@ export function FeedEntry(props: FeedEntryProps) {
|
|||||||
if (viewMode === "title" || viewMode === "cozy") paddingX = 6
|
if (viewMode === "title" || viewMode === "cozy") paddingX = 6
|
||||||
|
|
||||||
let paddingY: MantineNumberSize = "xs"
|
let paddingY: MantineNumberSize = "xs"
|
||||||
if (viewMode === "title") paddingY = 4
|
if (viewMode === "title") {
|
||||||
else if (viewMode === "cozy") paddingY = 8
|
paddingY = 4
|
||||||
|
} else if (viewMode === "cozy") {
|
||||||
|
paddingY = 8
|
||||||
|
}
|
||||||
|
|
||||||
let borderRadius: MantineNumberSize = "sm"
|
let borderRadius: MantineNumberSize = "sm"
|
||||||
if (viewMode === "title") borderRadius = 0
|
if (viewMode === "title") {
|
||||||
else if (viewMode === "cozy") borderRadius = "xs"
|
borderRadius = 0
|
||||||
|
} else if (viewMode === "cozy") {
|
||||||
|
borderRadius = "xs"
|
||||||
|
}
|
||||||
|
|
||||||
const compactHeader = !props.expanded && (viewMode === "title" || viewMode === "cozy")
|
const compactHeader = !props.expanded && (viewMode === "title" || viewMode === "cozy")
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries"
|
|||||||
import { redirectToFeed } from "app/slices/redirect"
|
import { redirectToFeed } from "app/slices/redirect"
|
||||||
import { useAppDispatch, useAppSelector } from "app/store"
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
import { Entry } from "app/types"
|
import { Entry } from "app/types"
|
||||||
import { openLinkInBackgroundTab, truncate } from "app/utils"
|
import { truncate } from "app/utils"
|
||||||
|
import { useBrowserExtension } from "hooks/useBrowserExtension"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import { Item, Menu, Separator, useContextMenu } from "react-contexify"
|
import { Item, Menu, Separator, useContextMenu } from "react-contexify"
|
||||||
import { TbArrowBarToDown, TbExternalLink, TbEyeCheck, TbEyeOff, TbRss, TbStar, TbStarOff } from "react-icons/tb"
|
import { TbArrowBarToDown, TbExternalLink, TbEyeCheck, TbEyeOff, TbRss, TbStar, TbStarOff } from "react-icons/tb"
|
||||||
@@ -34,6 +35,7 @@ export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
|
|||||||
const { classes, theme } = useStyles()
|
const { classes, theme } = useStyles()
|
||||||
const sourceType = useAppSelector(state => state.entries.source.type)
|
const sourceType = useAppSelector(state => state.entries.source.type)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
const { openLinkInBackgroundTab } = useBrowserExtension()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu id={menuId(props.entry)} theme={theme.colorScheme} animation={false} className={classes.menu}>
|
<Menu id={menuId(props.entry)} theme={theme.colorScheme} animation={false} className={classes.menu}>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export function Header() {
|
|||||||
const settings = useAppSelector(state => state.user.settings)
|
const settings = useAppSelector(state => state.user.settings)
|
||||||
const profile = useAppSelector(state => state.user.profile)
|
const profile = useAppSelector(state => state.user.profile)
|
||||||
const searchFromStore = useAppSelector(state => state.entries.search)
|
const searchFromStore = useAppSelector(state => state.entries.search)
|
||||||
const { isBrowserExtension, openSettingsPage, openAppInNewTab } = useBrowserExtension()
|
const { isBrowserExtensionPopup, openSettingsPage, openAppInNewTab } = useBrowserExtension()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
const searchForm = useForm<{ search: string }>({
|
const searchForm = useForm<{ search: string }>({
|
||||||
@@ -90,7 +90,7 @@ export function Header() {
|
|||||||
|
|
||||||
<ProfileMenu control={<ActionButton icon={<TbUser size={iconSize} />} label={profile?.name} />} />
|
<ProfileMenu control={<ActionButton icon={<TbUser size={iconSize} />} label={profile?.name} />} />
|
||||||
|
|
||||||
{isBrowserExtension && (
|
{isBrowserExtensionPopup && (
|
||||||
<>
|
<>
|
||||||
<HeaderDivider />
|
<HeaderDivider />
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,64 @@
|
|||||||
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
export const useBrowserExtension = () => {
|
export const useBrowserExtension = () => {
|
||||||
|
// the extension will set the "browser-extension-installed" attribute on the root element
|
||||||
|
const [browserExtensionVersion, setBrowserExtensionVersion] = useState(
|
||||||
|
document.documentElement.getAttribute("browser-extension-installed")
|
||||||
|
)
|
||||||
|
|
||||||
|
// monitor the attribute on the root element as it may change after the page was loaded
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new MutationObserver(mutations => {
|
||||||
|
mutations.forEach(mutation => {
|
||||||
|
if (mutation.type === "attributes") {
|
||||||
|
const element = mutation.target as Element
|
||||||
|
const version = element.getAttribute("browser-extension-installed")
|
||||||
|
if (version) setBrowserExtensionVersion(version)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
observer.observe(document.documentElement, {
|
||||||
|
attributes: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => observer.disconnect()
|
||||||
|
}, [])
|
||||||
|
|
||||||
// when not in an iframe, window.parent is a reference to window
|
// when not in an iframe, window.parent is a reference to window
|
||||||
const isBrowserExtension = window.parent !== window
|
const isBrowserExtensionPopup = window.parent !== window
|
||||||
|
const isBrowserExtensionInstalled = isBrowserExtensionPopup || !!browserExtensionVersion
|
||||||
|
const isBrowserExtensionInstallable = !isBrowserExtensionPopup
|
||||||
|
|
||||||
const openSettingsPage = () => window.parent.postMessage("open-settings-page", "*")
|
const w = isBrowserExtensionPopup ? window.parent : window
|
||||||
const openAppInNewTab = () => window.parent.postMessage("open-app-in-new-tab", "*")
|
const openSettingsPage = () => w.postMessage("open-settings-page", "*")
|
||||||
|
const openAppInNewTab = () => w.postMessage("open-app-in-new-tab", "*")
|
||||||
|
const openLinkInBackgroundTab = (url: string) => {
|
||||||
|
if (isBrowserExtensionInstalled) {
|
||||||
|
w.postMessage(`open-link-in-background-tab:${url}`, "*")
|
||||||
|
} else {
|
||||||
|
// fallback to ctrl+click simulation
|
||||||
|
const a = document.createElement("a")
|
||||||
|
a.href = url
|
||||||
|
a.rel = "noreferrer"
|
||||||
|
a.dispatchEvent(
|
||||||
|
new MouseEvent("click", {
|
||||||
|
ctrlKey: true,
|
||||||
|
metaKey: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const setBadgeUnreadCount = (count: number) => w.postMessage(`set-badge-unread-count:${count}`, "*")
|
||||||
|
|
||||||
return { isBrowserExtension, openSettingsPage, openAppInNewTab }
|
return {
|
||||||
|
browserExtensionVersion,
|
||||||
|
isBrowserExtensionInstallable,
|
||||||
|
isBrowserExtensionInstalled,
|
||||||
|
isBrowserExtensionPopup,
|
||||||
|
openSettingsPage,
|
||||||
|
openAppInNewTab,
|
||||||
|
openLinkInBackgroundTab,
|
||||||
|
setBadgeUnreadCount,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "العودة"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "العودة لتسجيل الدخول"
|
msgstr "العودة لتسجيل الدخول"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "ملحقات المستعرض"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "سيؤدي تغيير كلمة المرور إلى إنشاء مفتاح
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "تأكد من عمل الخلاصة"
|
msgstr "تأكد من عمل الخلاصة"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed التالي العنصر غير المقروء"
|
msgstr "CommaFeed التالي العنصر غير المقروء"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "إصدار CommaFeed {الإصدار} ({مراجعة})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "الموضوع"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "تبديل قراءة حالة الإدخال الحالي"
|
msgstr "تبديل قراءة حالة الإدخال الحالي"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "جرب CommaFeed باستخدام الحساب التجريبي: تجريبي / تجريبي"
|
msgstr "جرب CommaFeed باستخدام الحساب التجريبي: تجريبي / تجريبي"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Enrere"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Tornar a iniciar sessió"
|
msgstr "Tornar a iniciar sessió"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Extensions del navegador"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Canviar la contrasenya generarà una nova clau d'API"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Comproveu que el canal funciona"
|
msgstr "Comproveu que el canal funciona"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed següent element no llegit"
|
msgstr "CommaFeed següent element no llegit"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "Versió CommaFeed {versió} ({revisió})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Canvia l'estat de lectura de l'entrada actual"
|
msgstr "Canvia l'estat de lectura de l'entrada actual"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Proveu CommaFeed amb el compte de demostració: demo/demo"
|
msgstr "Proveu CommaFeed amb el compte de demostració: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Zpět"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Zpět k přihlášení"
|
msgstr "Zpět k přihlášení"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Rozšíření prohlížeče"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Změna hesla vygeneruje nový klíč API"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Zkontrolujte, zda zdroj funguje"
|
msgstr "Zkontrolujte, zda zdroj funguje"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed další nepřečtená položka"
|
msgstr "CommaFeed další nepřečtená položka"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed verze {version} ({revision})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Téma"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Přepne stav čtení aktuálního záznamu"
|
msgstr "Přepne stav čtení aktuálního záznamu"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Vyzkoušejte CommaFeed s demo účtem: demo/demo"
|
msgstr "Vyzkoušejte CommaFeed s demo účtem: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Yn ôl"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Yn ôl i fewngofnodi"
|
msgstr "Yn ôl i fewngofnodi"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Estyniadau porwr"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Bydd newid cyfrinair yn cynhyrchu allwedd API newydd"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Gwiriwch fod y porthiant yn gweithio"
|
msgstr "Gwiriwch fod y porthiant yn gweithio"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed eitem nesaf heb ei darllen"
|
msgstr "CommaFeed eitem nesaf heb ei darllen"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "Fersiwn ComaFeed {fersiwn} ({ adolygu})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Thema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Toglo statws darllen y cofnod cyfredol"
|
msgstr "Toglo statws darllen y cofnod cyfredol"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Rhowch gynnig ar CommaFeed gyda'r cyfrif demo: demo / demo"
|
msgstr "Rhowch gynnig ar CommaFeed gyda'r cyfrif demo: demo / demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Tilbage"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Tilbage for at logge ind"
|
msgstr "Tilbage for at logge ind"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Browserudvidelser"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,12 +167,16 @@ msgstr "Ændring af adgangskode vil generere en ny API-nøgle"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Tjek, at foderet virker"
|
msgstr "Tjek, at foderet virker"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed næste ulæste element"
|
msgstr "CommaFeed næste ulæste element"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Skift læsestatus for den aktuelle post"
|
msgstr "Skift læsestatus for den aktuelle post"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Prøv CommaFeed med demokontoen: demo/demo"
|
msgstr "Prøv CommaFeed med demokontoen: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Zurück"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Zurück zum Anmelden"
|
msgstr "Zurück zum Anmelden"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Browsererweiterungen"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Das Ändern des Passworts generiert einen neuen API-Schlüssel"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Überprüfen Sie, ob der Feed funktioniert"
|
msgstr "Überprüfen Sie, ob der Feed funktioniert"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed nächstes ungelesenes Element"
|
msgstr "CommaFeed nächstes ungelesenes Element"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed-Version {Version} ({Revision})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Thema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Lesestatus des aktuellen Eintrags umschalten"
|
msgstr "Lesestatus des aktuellen Eintrags umschalten"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Testen Sie CommaFeed mit dem Demokonto: demo/demo"
|
msgstr "Testen Sie CommaFeed mit dem Demokonto: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Back"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Back to log in"
|
msgstr "Back to log in"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr "Browser extension required for Chrome"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Browser extentions"
|
msgstr "Browser extention"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Changing password will generate a new API key"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Check that the feed is working"
|
msgstr "Check that the feed is working"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed next unread item"
|
msgstr "CommaFeed next unread item"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed version {version} ({revision})"
|
msgstr "CommaFeed version {version} ({revision})."
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Theme"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Toggle read status of current entry"
|
msgstr "Toggle read status of current entry"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr "Toggle sidebar"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Try out CommaFeed with the demo account: demo/demo"
|
msgstr "Try out CommaFeed with the demo account: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Atrás"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Volver a iniciar sesión"
|
msgstr "Volver a iniciar sesión"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Extensiones del navegador"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Cambiar la contraseña generará una nueva clave API"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Compruebe que el feed funciona"
|
msgstr "Compruebe que el feed funciona"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed siguiente elemento no leído"
|
msgstr "CommaFeed siguiente elemento no leído"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "versión de CommaFeed {versión} ({revisión})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Alternar estado de lectura de la entrada actual"
|
msgstr "Alternar estado de lectura de la entrada actual"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Pruebe CommaFeed con la cuenta demo: demo/demo"
|
msgstr "Pruebe CommaFeed con la cuenta demo: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "برگشت"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "بازگشت برای ورود به سیستم"
|
msgstr "بازگشت برای ورود به سیستم"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "گسترش مرورگر"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "تغییر رمز عبور یک کلید API جدید ایجاد می ک
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "بررسی کنید که خوراک کار می کند"
|
msgstr "بررسی کنید که خوراک کار می کند"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "مورد خوانده نشده بعدی CommaFeed"
|
msgstr "مورد خوانده نشده بعدی CommaFeed"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "نسخه {نسخه} CommaFeed ({نسخه})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "تم"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "وضعیت خواندن ورودی فعلی را تغییر دهید"
|
msgstr "وضعیت خواندن ورودی فعلی را تغییر دهید"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "CommaFeed را با حساب آزمایشی امتحان کنید: دمو/دمو"
|
msgstr "CommaFeed را با حساب آزمایشی امتحان کنید: دمو/دمو"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Takaisin"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Takaisin sisäänkirjautumiseen"
|
msgstr "Takaisin sisäänkirjautumiseen"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Selaimen laajennukset"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Salasanan vaihtaminen luo uuden API-avaimen"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Tarkista, että syöttö toimii"
|
msgstr "Tarkista, että syöttö toimii"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed seuraava lukematon kohde"
|
msgstr "CommaFeed seuraava lukematon kohde"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed-versio {version} ({versio})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Teema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Vaihda nykyisen merkinnän lukutila"
|
msgstr "Vaihda nykyisen merkinnän lukutila"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Kokeile CommaFeediä demotilillä: demo/demo"
|
msgstr "Kokeile CommaFeediä demotilillä: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Retour"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Retour à la connexion"
|
msgstr "Retour à la connexion"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Extensions pour navigateurs"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Changer de mot de passe générera une nouvelle clé API"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Vérifie que le flux fonctionne"
|
msgstr "Vérifie que le flux fonctionne"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed prochain article non lu"
|
msgstr "CommaFeed prochain article non lu"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed version {version} ({revision})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Thème"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Marquer l'entrée actuelle comme lue/non lue"
|
msgstr "Marquer l'entrée actuelle comme lue/non lue"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Essayez CommaFeed avec le compte de démonstration : demo/demo"
|
msgstr "Essayez CommaFeed avec le compte de démonstration : demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Atrás"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Volver para iniciar sesión"
|
msgstr "Volver para iniciar sesión"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Extensións do navegador"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "O cambio de contrasinal xerará unha nova clave de API"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Comproba que a fonte funciona"
|
msgstr "Comproba que a fonte funciona"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed seguinte elemento non lido"
|
msgstr "CommaFeed seguinte elemento non lido"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "Versión de CommaFeed {versión} ({revisión})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "alternar o estado de lectura da entrada actual"
|
msgstr "alternar o estado de lectura da entrada actual"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Proba CommaFeed coa conta de demostración: demo/demo"
|
msgstr "Proba CommaFeed coa conta de demostración: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Vissza"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Vissza a bejelentkezéshez"
|
msgstr "Vissza a bejelentkezéshez"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Böngészőbővítések"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "A jelszó megváltoztatása új API-kulcsot generál"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Ellenőrizze, hogy a feed működik-e"
|
msgstr "Ellenőrizze, hogy a feed működik-e"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed következő olvasatlan elem"
|
msgstr "CommaFeed következő olvasatlan elem"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed verzió {version} ({revision})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Téma"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Az aktuális bejegyzés olvasási állapotának váltása"
|
msgstr "Az aktuális bejegyzés olvasási állapotának váltása"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Próbálja ki a CommaFeed-et a demo fiókkal: demo/demo"
|
msgstr "Próbálja ki a CommaFeed-et a demo fiókkal: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Kembali"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Kembali untuk masuk"
|
msgstr "Kembali untuk masuk"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Ekstensi peramban"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Mengubah kata sandi akan menghasilkan kunci API baru"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Periksa apakah umpannya berfungsi"
|
msgstr "Periksa apakah umpannya berfungsi"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed item yang belum dibaca berikutnya"
|
msgstr "CommaFeed item yang belum dibaca berikutnya"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed versi {versi} ({revisi})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Beralih status baca entri saat ini"
|
msgstr "Beralih status baca entri saat ini"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Cobalah CommaFeed dengan akun demo: demo/demo"
|
msgstr "Cobalah CommaFeed dengan akun demo: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Indietro"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Torna per accedere"
|
msgstr "Torna per accedere"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Estensioni del browser"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "La modifica della password genererà una nuova chiave API"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Verifica che il feed funzioni"
|
msgstr "Verifica che il feed funzioni"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed successivo elemento non letto"
|
msgstr "CommaFeed successivo elemento non letto"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "Versione CommaFeed {versione} ({revisione})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Commuta lo stato di lettura della voce corrente"
|
msgstr "Commuta lo stato di lettura della voce corrente"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Prova CommaFeed con il conto demo: demo/demo"
|
msgstr "Prova CommaFeed con il conto demo: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "裏"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "ログインに戻る"
|
msgstr "ログインに戻る"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "ブラウザ拡張機能"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "パスワードを変更すると、新しい API キーが生成され
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "フィードが動作していることを確認してください"
|
msgstr "フィードが動作していることを確認してください"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "次の未読アイテムをカンマフィード"
|
msgstr "次の未読アイテムをカンマフィード"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "コンマフィードのバージョン {version} ({revision})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "テーマ"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "現在のエントリの読み取りステータスを切り替えます"
|
msgstr "現在のエントリの読み取りステータスを切り替えます"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "デモアカウントで CommaFeed を試す: demo/demo"
|
msgstr "デモアカウントで CommaFeed を試す: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "뒤로"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "로그인으로 돌아가기"
|
msgstr "로그인으로 돌아가기"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "브라우저 확장"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "비밀번호를 변경하면 새 API 키가 생성됩니다."
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "피드가 작동하는지 확인"
|
msgstr "피드가 작동하는지 확인"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "다음 읽지 않은 항목을 쉼표로 피드"
|
msgstr "다음 읽지 않은 항목을 쉼표로 피드"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "쉼표 피드 버전 {버전}({개정})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "테마"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "현재 항목의 읽기 상태 전환"
|
msgstr "현재 항목의 읽기 상태 전환"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "데모 계정으로 CommaFeed를 사용해 보세요: demo/demo"
|
msgstr "데모 계정으로 CommaFeed를 사용해 보세요: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Kembali"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Kembali untuk log masuk"
|
msgstr "Kembali untuk log masuk"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Peluasan penyemak imbas"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Menukar kata laluan akan menjana kunci API baharu"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Semak sama ada suapan berfungsi"
|
msgstr "Semak sama ada suapan berfungsi"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed item belum dibaca seterusnya"
|
msgstr "CommaFeed item belum dibaca seterusnya"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "Versi CommaFeed {versi} ({semakan})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Togol status bacaan entri semasa"
|
msgstr "Togol status bacaan entri semasa"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Cuba CommaFeed dengan akaun demo: demo/demo"
|
msgstr "Cuba CommaFeed dengan akaun demo: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Tilbake"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Tilbake for å logge inn"
|
msgstr "Tilbake for å logge inn"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Nettleserutvidelser"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Endring av passord vil generere en ny API-nøkkel"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Sjekk at feeden fungerer"
|
msgstr "Sjekk at feeden fungerer"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed neste uleste element"
|
msgstr "CommaFeed neste uleste element"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed versjon {versjon} ({revisjon})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Veksle lesestatus for gjeldende oppføring"
|
msgstr "Veksle lesestatus for gjeldende oppføring"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Prøv CommaFeed med demokontoen: demo/demo"
|
msgstr "Prøv CommaFeed med demokontoen: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Terug"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Terug naar inloggen"
|
msgstr "Terug naar inloggen"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Browserextensies"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Het wijzigen van het wachtwoord genereert een nieuwe API-sleutel"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Controleer of de feed werkt"
|
msgstr "Controleer of de feed werkt"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed volgende ongelezen item"
|
msgstr "CommaFeed volgende ongelezen item"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed-versie {versie} ({revisie})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Thema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Toggle leesstatus van huidige invoer"
|
msgstr "Toggle leesstatus van huidige invoer"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Probeer CommaFeed uit met het demo-account: demo/demo"
|
msgstr "Probeer CommaFeed uit met het demo-account: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Tilbake"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Tilbake for å logge inn"
|
msgstr "Tilbake for å logge inn"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Nettleserutvidelser"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Endring av passord vil generere en ny API-nøkkel"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Sjekk at feeden fungerer"
|
msgstr "Sjekk at feeden fungerer"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed neste uleste element"
|
msgstr "CommaFeed neste uleste element"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed versjon {versjon} ({revisjon})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Veksle lesestatus for gjeldende oppføring"
|
msgstr "Veksle lesestatus for gjeldende oppføring"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Prøv CommaFeed med demokontoen: demo/demo"
|
msgstr "Prøv CommaFeed med demokontoen: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Powrót"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Powrót do logowania"
|
msgstr "Powrót do logowania"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Rozszerzenia przeglądarki"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Zmiana hasła spowoduje wygenerowanie nowego klucza API"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Sprawdź, czy kanał działa"
|
msgstr "Sprawdź, czy kanał działa"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "Przecinek następny nieprzeczytany element"
|
msgstr "Przecinek następny nieprzeczytany element"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "Wersja CommaFeed {wersja} ({wersja})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Motyw"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Przełącz stan odczytu bieżącego wpisu"
|
msgstr "Przełącz stan odczytu bieżącego wpisu"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Wypróbuj CommaFeed z kontem demo: demo/demo"
|
msgstr "Wypróbuj CommaFeed z kontem demo: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Voltar"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Voltar para logar"
|
msgstr "Voltar para logar"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Extensões do navegador"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "A alteração da senha gerará uma nova chave de API"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Verifique se o feed está funcionando"
|
msgstr "Verifique se o feed está funcionando"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed próximo item não lido"
|
msgstr "CommaFeed próximo item não lido"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "Versão do CommaFeed {versão} ({revisão})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Alternar o status de leitura da entrada atual"
|
msgstr "Alternar o status de leitura da entrada atual"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Experimente o CommaFeed com a conta demo: demo/demo"
|
msgstr "Experimente o CommaFeed com a conta demo: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Назад"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Вернуться к входу"
|
msgstr "Вернуться к входу"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Расширения браузера"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "При изменении пароля будет сгенерирова
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Проверьте, работает ли лента."
|
msgstr "Проверьте, работает ли лента."
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed следующий непрочитанный элемент"
|
msgstr "CommaFeed следующий непрочитанный элемент"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed версия {версия} ({редакция})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Тема"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Переключить статус чтения текущей записи"
|
msgstr "Переключить статус чтения текущей записи"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Попробуйте CommaFeed на демо-счете: demo/demo"
|
msgstr "Попробуйте CommaFeed на демо-счете: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Späť"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Späť na prihlásenie"
|
msgstr "Späť na prihlásenie"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Rozšírenia prehliadača"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Zmena hesla vygeneruje nový kľúč API"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Skontrolujte, či feed funguje"
|
msgstr "Skontrolujte, či feed funguje"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed ďalšia neprečítaná položka"
|
msgstr "CommaFeed ďalšia neprečítaná položka"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed verzia {version} ({revision})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Téma"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Prepne stav čítania aktuálneho záznamu"
|
msgstr "Prepne stav čítania aktuálneho záznamu"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Vyskúšajte CommaFeed s demo účtom: demo/demo"
|
msgstr "Vyskúšajte CommaFeed s demo účtom: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Tillbaka"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Tillbaka för att logga in"
|
msgstr "Tillbaka för att logga in"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Webbläsartillägg"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,12 +167,16 @@ msgstr "Ändra lösenord kommer att generera en ny API-nyckel"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Kontrollera att matningen fungerar"
|
msgstr "Kontrollera att matningen fungerar"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed nästa olästa objekt"
|
msgstr "CommaFeed nästa olästa objekt"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Växla lässtatus för aktuell post"
|
msgstr "Växla lässtatus för aktuell post"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Prova CommaFeed med demokontot: demo/demo"
|
msgstr "Prova CommaFeed med demokontot: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "Geri"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Giriş yapmak için geri dön"
|
msgstr "Giriş yapmak için geri dön"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "Tarayıcı uzantıları"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "Şifreyi değiştirmek yeni bir API anahtarı oluşturacak"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "Feed'in çalışıp çalışmadığını kontrol edin"
|
msgstr "Feed'in çalışıp çalışmadığını kontrol edin"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed sonraki okunmamış öğe"
|
msgstr "CommaFeed sonraki okunmamış öğe"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed sürümü {sürüm} ({revizyon})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "Tema"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Geçerli girişin okuma durumunu değiştir"
|
msgstr "Geçerli girişin okuma durumunu değiştir"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "CommaFeed'i demo hesabıyla deneyin: demo/demo"
|
msgstr "CommaFeed'i demo hesabıyla deneyin: demo/demo"
|
||||||
|
|||||||
@@ -127,9 +127,13 @@ msgstr "返回"
|
|||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "返回登录"
|
msgstr "返回登录"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Browser extension required for Chrome"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extentions"
|
msgid "Browser extention"
|
||||||
msgstr "浏览器扩展"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
@@ -163,13 +167,17 @@ msgstr "更改密码将生成新的 API 密钥"
|
|||||||
msgid "Check that the feed is working"
|
msgid "Check that the feed is working"
|
||||||
msgstr "检查提要是否正常工作"
|
msgstr "检查提要是否正常工作"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
msgstr "CommaFeed 下一个未读项目"
|
msgstr "CommaFeed 下一个未读项目"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed version {version} ({revision})"
|
msgid "CommaFeed version {version} ({revision})."
|
||||||
msgstr "CommaFeed 版本 {version} ({revision})"
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
@@ -793,6 +801,10 @@ msgstr "主题"
|
|||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "切换当前条目的读取状态"
|
msgstr "切换当前条目的读取状态"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Toggle sidebar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "使用演示帐户试用 CommaFeed:demo/demo"
|
msgstr "使用演示帐户试用 CommaFeed:demo/demo"
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ function Buttons() {
|
|||||||
const iconSize = 18
|
const iconSize = 18
|
||||||
const serverInfos = useAppSelector(state => state.server.serverInfos)
|
const serverInfos = useAppSelector(state => state.server.serverInfos)
|
||||||
const { colorScheme, toggleColorScheme } = useMantineColorScheme()
|
const { colorScheme, toggleColorScheme } = useMantineColorScheme()
|
||||||
const { isBrowserExtension, openSettingsPage } = useBrowserExtension()
|
const { isBrowserExtensionPopup, openSettingsPage } = useBrowserExtension()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const dark = colorScheme === "dark"
|
const dark = colorScheme === "dark"
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ function Buttons() {
|
|||||||
hideLabelOnDesktop
|
hideLabelOnDesktop
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{isBrowserExtension && (
|
{isBrowserExtensionPopup && (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={<Trans>Extension options</Trans>}
|
label={<Trans>Extension options</Trans>}
|
||||||
icon={<TbSettings size={iconSize} />}
|
icon={<TbSettings size={iconSize} />}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { redirectToApiDocumentation } from "app/slices/redirect"
|
|||||||
import { useAppDispatch, useAppSelector } from "app/store"
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
import { CategorySelect } from "components/content/add/CategorySelect"
|
import { CategorySelect } from "components/content/add/CategorySelect"
|
||||||
import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp"
|
import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp"
|
||||||
|
import { useBrowserExtension } from "hooks/useBrowserExtension"
|
||||||
import React, { useState } from "react"
|
import React, { useState } from "react"
|
||||||
import { TbHelp, TbKeyboard, TbPuzzle, TbRocket } from "react-icons/tb"
|
import { TbHelp, TbKeyboard, TbPuzzle, TbRocket } from "react-icons/tb"
|
||||||
|
|
||||||
@@ -60,16 +61,23 @@ function NextUnreadBookmarklet() {
|
|||||||
export function AboutPage() {
|
export function AboutPage() {
|
||||||
const version = useAppSelector(state => state.server.serverInfos?.version)
|
const version = useAppSelector(state => state.server.serverInfos?.version)
|
||||||
const revision = useAppSelector(state => state.server.serverInfos?.gitCommit)
|
const revision = useAppSelector(state => state.server.serverInfos?.gitCommit)
|
||||||
|
const { isBrowserExtensionInstalled, browserExtensionVersion, isBrowserExtensionInstallable } = useBrowserExtension()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container size="xl">
|
<Container size="xl">
|
||||||
<SimpleGrid cols={2} breakpoints={[{ maxWidth: Constants.layout.mobileBreakpoint, cols: 1 }]}>
|
<SimpleGrid cols={2} breakpoints={[{ maxWidth: Constants.layout.mobileBreakpoint, cols: 1 }]}>
|
||||||
<Section title={<Trans>About</Trans>} icon={<TbHelp size={24} />}>
|
<Section title={<Trans>About</Trans>} icon={<TbHelp size={24} />}>
|
||||||
<Box>
|
<Box>
|
||||||
<Trans>
|
<Trans>
|
||||||
CommaFeed version {version} ({revision})
|
CommaFeed version {version} ({revision}).
|
||||||
</Trans>
|
</Trans>
|
||||||
</Box>
|
</Box>
|
||||||
|
{isBrowserExtensionInstallable && isBrowserExtensionInstalled && (
|
||||||
|
<Box>
|
||||||
|
<Trans>CommaFeed browser extension version {browserExtensionVersion}.</Trans>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
<Box mt="md">
|
<Box mt="md">
|
||||||
<Trans>
|
<Trans>
|
||||||
<span>CommaFeed is an open-source project. Sources are hosted on </span>
|
<span>CommaFeed is an open-source project. Sources are hosted on </span>
|
||||||
@@ -86,8 +94,8 @@ export function AboutPage() {
|
|||||||
<Section title={<Trans>Goodies</Trans>} icon={<TbPuzzle size={24} />}>
|
<Section title={<Trans>Goodies</Trans>} icon={<TbPuzzle size={24} />}>
|
||||||
<List>
|
<List>
|
||||||
<List.Item>
|
<List.Item>
|
||||||
<Anchor href="https://github.com/Athou/commafeed-browser-extension" target="_blank" rel="noreferrer">
|
<Anchor href={Constants.browserExtensionUrl} target="_blank" rel="noreferrer">
|
||||||
<Trans>Browser extentions</Trans>
|
<Trans>Browser extention</Trans>
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</List.Item>
|
</List.Item>
|
||||||
<List.Item>
|
<List.Item>
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
|
import { Box } from "@mantine/core"
|
||||||
import SwaggerUI from "swagger-ui-react"
|
import SwaggerUI from "swagger-ui-react"
|
||||||
import "swagger-ui-react/swagger-ui.css"
|
import "swagger-ui-react/swagger-ui.css"
|
||||||
|
|
||||||
function ApiDocumentationPage() {
|
function ApiDocumentationPage() {
|
||||||
return <SwaggerUI url="swagger/swagger.json" />
|
return (
|
||||||
|
// force white background because swagger is unreadable with dark theme
|
||||||
|
<Box style={{ backgroundColor: "#fff" }}>
|
||||||
|
<SwaggerUI url="swagger/swagger.json" />
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ApiDocumentationPage
|
export default ApiDocumentationPage
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import {
|
|||||||
Title,
|
Title,
|
||||||
useMantineTheme,
|
useMantineTheme,
|
||||||
} from "@mantine/core"
|
} from "@mantine/core"
|
||||||
import { useViewportSize } from "@mantine/hooks"
|
import { useMediaQuery, useViewportSize } from "@mantine/hooks"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import { redirectToAdd, redirectToRootCategory } from "app/slices/redirect"
|
import { redirectToAdd, redirectToRootCategory } from "app/slices/redirect"
|
||||||
import { reloadTree, setMobileMenuOpen } from "app/slices/tree"
|
import { reloadTree, setMobileMenuOpen, setSidebarWidth } from "app/slices/tree"
|
||||||
import { reloadProfile, reloadSettings, reloadTags } from "app/slices/user"
|
import { reloadProfile, reloadSettings, reloadTags } from "app/slices/user"
|
||||||
import { useAppDispatch, useAppSelector } from "app/store"
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
import { Loader } from "components/Loader"
|
import { Loader } from "components/Loader"
|
||||||
@@ -26,28 +26,39 @@ import { OnMobile } from "components/responsive/OnMobile"
|
|||||||
import { useAppLoading } from "hooks/useAppLoading"
|
import { useAppLoading } from "hooks/useAppLoading"
|
||||||
import { useWebSocket } from "hooks/useWebSocket"
|
import { useWebSocket } from "hooks/useWebSocket"
|
||||||
import { LoadingPage } from "pages/LoadingPage"
|
import { LoadingPage } from "pages/LoadingPage"
|
||||||
|
import { Resizable } from "re-resizable"
|
||||||
import { ReactNode, Suspense, useEffect } from "react"
|
import { ReactNode, Suspense, useEffect } from "react"
|
||||||
import { TbPlus } from "react-icons/tb"
|
import { TbPlus } from "react-icons/tb"
|
||||||
import { Outlet } from "react-router-dom"
|
import { Outlet } from "react-router-dom"
|
||||||
|
|
||||||
interface LayoutProps {
|
interface LayoutProps {
|
||||||
sidebar: ReactNode
|
sidebar: ReactNode
|
||||||
|
sidebarWidth: number
|
||||||
header: ReactNode
|
header: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
const sidebarPadding = DEFAULT_THEME.spacing.xs
|
const sidebarPadding = DEFAULT_THEME.spacing.xs
|
||||||
const sidebarRightBorderWidth = "1px"
|
const sidebarRightBorderWidth = "1px"
|
||||||
|
|
||||||
const useStyles = createStyles(theme => ({
|
const useStyles = createStyles((theme, props: LayoutProps) => ({
|
||||||
|
sidebar: {
|
||||||
|
"& .mantine-ScrollArea-scrollbar[data-orientation='horizontal']": {
|
||||||
|
display: "none",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sidebarContentResizeWrapper: {
|
||||||
|
padding: sidebarPadding,
|
||||||
|
minHeight: `calc(100vh - ${Constants.layout.headerHeight}px)`,
|
||||||
|
},
|
||||||
sidebarContent: {
|
sidebarContent: {
|
||||||
maxWidth: `calc(${Constants.layout.sidebarWidth}px - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`,
|
maxWidth: `calc(${props.sidebarWidth}px - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`,
|
||||||
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
||||||
maxWidth: `calc(100vw - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`,
|
maxWidth: `calc(100vw - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mainContentWrapper: {
|
mainContentWrapper: {
|
||||||
paddingTop: Constants.layout.headerHeight,
|
paddingTop: Constants.layout.headerHeight,
|
||||||
paddingLeft: Constants.layout.sidebarWidth,
|
paddingLeft: props.sidebarWidth,
|
||||||
paddingRight: 0,
|
paddingRight: 0,
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
||||||
@@ -55,7 +66,7 @@ const useStyles = createStyles(theme => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mainContent: {
|
mainContent: {
|
||||||
maxWidth: `calc(100vw - ${Constants.layout.sidebarWidth}px)`,
|
maxWidth: `calc(100vw - ${props.sidebarWidth}px)`,
|
||||||
padding: theme.spacing.md,
|
padding: theme.spacing.md,
|
||||||
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
||||||
maxWidth: "100vw",
|
maxWidth: "100vw",
|
||||||
@@ -76,15 +87,19 @@ function LogoAndTitle() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Layout({ sidebar, header }: LayoutProps) {
|
export default function Layout(props: LayoutProps) {
|
||||||
const { classes } = useStyles()
|
const { classes } = useStyles(props)
|
||||||
const theme = useMantineTheme()
|
const theme = useMantineTheme()
|
||||||
const viewport = useViewportSize()
|
const viewport = useViewportSize()
|
||||||
const { loading } = useAppLoading()
|
const { loading } = useAppLoading()
|
||||||
|
const mobile = !useMediaQuery(`(min-width: ${Constants.layout.mobileBreakpoint})`)
|
||||||
const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen)
|
const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen)
|
||||||
|
const sidebarHidden = props.sidebarWidth === 0
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
useWebSocket()
|
useWebSocket()
|
||||||
|
|
||||||
|
const handleResize = (element: HTMLElement) => dispatch(setSidebarWidth(element.offsetWidth))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(reloadSettings())
|
dispatch(reloadSettings())
|
||||||
dispatch(reloadProfile())
|
dispatch(reloadProfile())
|
||||||
@@ -122,13 +137,29 @@ export default function Layout({ sidebar, header }: LayoutProps) {
|
|||||||
navbar={
|
navbar={
|
||||||
<Navbar
|
<Navbar
|
||||||
id="sidebar"
|
id="sidebar"
|
||||||
p={sidebarPadding}
|
hiddenBreakpoint={sidebarHidden ? 99999999 : Constants.layout.mobileBreakpoint}
|
||||||
hiddenBreakpoint={Constants.layout.mobileBreakpoint}
|
hidden={sidebarHidden || !mobileMenuOpen}
|
||||||
hidden={!mobileMenuOpen}
|
width={{ md: props.sidebarWidth }}
|
||||||
width={{ md: Constants.layout.sidebarWidth }}
|
className={classes.sidebar}
|
||||||
>
|
>
|
||||||
<Navbar.Section grow component={ScrollArea} mx="-xs" px="xs">
|
<Navbar.Section grow component={ScrollArea} mx={mobile ? 0 : "-sm"} px={mobile ? 0 : "sm"}>
|
||||||
<Box className={classes.sidebarContent}>{sidebar}</Box>
|
<Resizable
|
||||||
|
enable={{
|
||||||
|
top: false,
|
||||||
|
right: !mobile,
|
||||||
|
bottom: false,
|
||||||
|
left: false,
|
||||||
|
topRight: false,
|
||||||
|
bottomRight: false,
|
||||||
|
bottomLeft: false,
|
||||||
|
topLeft: false,
|
||||||
|
}}
|
||||||
|
onResize={(e, dir, el) => handleResize(el)}
|
||||||
|
minWidth={120}
|
||||||
|
className={classes.sidebarContentResizeWrapper}
|
||||||
|
>
|
||||||
|
<Box className={classes.sidebarContent}>{props.sidebar}</Box>
|
||||||
|
</Resizable>
|
||||||
</Navbar.Section>
|
</Navbar.Section>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
}
|
}
|
||||||
@@ -147,19 +178,19 @@ export default function Layout({ sidebar, header }: LayoutProps) {
|
|||||||
{!mobileMenuOpen && (
|
{!mobileMenuOpen && (
|
||||||
<Group>
|
<Group>
|
||||||
<Box mr="sm">{burger}</Box>
|
<Box mr="sm">{burger}</Box>
|
||||||
<Box sx={{ flexGrow: 1 }}>{header}</Box>
|
<Box sx={{ flexGrow: 1 }}>{props.header}</Box>
|
||||||
</Group>
|
</Group>
|
||||||
)}
|
)}
|
||||||
</OnMobile>
|
</OnMobile>
|
||||||
<OnDesktop>
|
<OnDesktop>
|
||||||
<Group>
|
<Group>
|
||||||
<Group position="apart" sx={{ width: Constants.layout.sidebarWidth - 16 }}>
|
<Group position="apart" sx={{ width: props.sidebarWidth - 16 }}>
|
||||||
<Box>
|
<Box>
|
||||||
<LogoAndTitle />
|
<LogoAndTitle />
|
||||||
</Box>
|
</Box>
|
||||||
<Box>{addButton}</Box>
|
<Box>{addButton}</Box>
|
||||||
</Group>
|
</Group>
|
||||||
<Box sx={{ flexGrow: 1 }}>{header}</Box>
|
<Box sx={{ flexGrow: 1 }}>{props.header}</Box>
|
||||||
</Group>
|
</Group>
|
||||||
</OnDesktop>
|
</OnDesktop>
|
||||||
</Header>
|
</Header>
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
app:
|
app:
|
||||||
# url used to access commafeed
|
# url used to access commafeed
|
||||||
publicUrl: http://localhost:8082/
|
publicUrl: http://localhost:8082/
|
||||||
|
|
||||||
|
# whether to expose a robots.txt file that disallows web crawlers and search engine indexers
|
||||||
|
hideFromWebCrawlers: true
|
||||||
|
|
||||||
# whether to allow user registrations
|
# whether to allow user registrations
|
||||||
allowRegistrations: true
|
allowRegistrations: true
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
app:
|
app:
|
||||||
# url used to access commafeed
|
# url used to access commafeed
|
||||||
publicUrl: http://localhost:8082/
|
publicUrl: http://localhost:8082/
|
||||||
|
|
||||||
|
# whether to expose a robots.txt file that disallows web crawlers and search engine indexers
|
||||||
|
hideFromWebCrawlers: true
|
||||||
|
|
||||||
# whether to allow user registrations
|
# whether to allow user registrations
|
||||||
allowRegistrations: false
|
allowRegistrations: false
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed</artifactId>
|
<artifactId>commafeed</artifactId>
|
||||||
<version>3.6.0</version>
|
<version>3.7.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>commafeed-server</artifactId>
|
<artifactId>commafeed-server</artifactId>
|
||||||
<name>CommaFeed Server</name>
|
<name>CommaFeed Server</name>
|
||||||
@@ -226,7 +226,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed-client</artifactId>
|
<artifactId>commafeed-client</artifactId>
|
||||||
<version>3.6.0</version>
|
<version>3.7.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import com.commafeed.frontend.servlet.CustomCssServlet;
|
|||||||
import com.commafeed.frontend.servlet.CustomJsServlet;
|
import com.commafeed.frontend.servlet.CustomJsServlet;
|
||||||
import com.commafeed.frontend.servlet.LogoutServlet;
|
import com.commafeed.frontend.servlet.LogoutServlet;
|
||||||
import com.commafeed.frontend.servlet.NextUnreadServlet;
|
import com.commafeed.frontend.servlet.NextUnreadServlet;
|
||||||
|
import com.commafeed.frontend.servlet.RobotsTxtDisallowAllServlet;
|
||||||
import com.commafeed.frontend.session.SessionHelperFactoryProvider;
|
import com.commafeed.frontend.session.SessionHelperFactoryProvider;
|
||||||
import com.commafeed.frontend.ws.WebSocketConfigurator;
|
import com.commafeed.frontend.ws.WebSocketConfigurator;
|
||||||
import com.commafeed.frontend.ws.WebSocketEndpoint;
|
import com.commafeed.frontend.ws.WebSocketEndpoint;
|
||||||
@@ -169,6 +170,11 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
|||||||
environment.servlets().addServlet("customCss", injector.getInstance(CustomCssServlet.class)).addMapping("/custom_css.css");
|
environment.servlets().addServlet("customCss", injector.getInstance(CustomCssServlet.class)).addMapping("/custom_css.css");
|
||||||
environment.servlets().addServlet("customJs", injector.getInstance(CustomJsServlet.class)).addMapping("/custom_js.js");
|
environment.servlets().addServlet("customJs", injector.getInstance(CustomJsServlet.class)).addMapping("/custom_js.js");
|
||||||
environment.servlets().addServlet("analytics.js", injector.getInstance(AnalyticsServlet.class)).addMapping("/analytics.js");
|
environment.servlets().addServlet("analytics.js", injector.getInstance(AnalyticsServlet.class)).addMapping("/analytics.js");
|
||||||
|
if (Boolean.TRUE.equals(config.getApplicationSettings().getHideFromWebCrawlers())) {
|
||||||
|
environment.servlets()
|
||||||
|
.addServlet("robots.txt", injector.getInstance(RobotsTxtDisallowAllServlet.class))
|
||||||
|
.addMapping("/robots.txt");
|
||||||
|
}
|
||||||
|
|
||||||
// WebSocket endpoint
|
// WebSocket endpoint
|
||||||
ServerEndpointConfig serverEndpointConfig = ServerEndpointConfig.Builder.create(WebSocketEndpoint.class, "/ws")
|
ServerEndpointConfig serverEndpointConfig = ServerEndpointConfig.Builder.create(WebSocketEndpoint.class, "/ws")
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ public class CommaFeedConfiguration extends Configuration {
|
|||||||
@Valid
|
@Valid
|
||||||
private String publicUrl;
|
private String publicUrl;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Valid
|
||||||
|
private Boolean hideFromWebCrawlers = true;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Valid
|
@Valid
|
||||||
private Boolean allowRegistrations;
|
private Boolean allowRegistrations;
|
||||||
|
|||||||
@@ -15,23 +15,30 @@ import com.commafeed.backend.model.QFeed;
|
|||||||
import com.commafeed.backend.model.QFeedSubscription;
|
import com.commafeed.backend.model.QFeedSubscription;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.querydsl.jpa.JPAExpressions;
|
import com.querydsl.jpa.JPAExpressions;
|
||||||
|
import com.querydsl.jpa.impl.JPAQuery;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedDAO extends GenericDAO<Feed> {
|
public class FeedDAO extends GenericDAO<Feed> {
|
||||||
|
|
||||||
private final QFeed feed = QFeed.feed;
|
private final QFeed feed = QFeed.feed;
|
||||||
|
private final QFeedSubscription subscription = QFeedSubscription.feedSubscription;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public FeedDAO(SessionFactory sessionFactory) {
|
public FeedDAO(SessionFactory sessionFactory) {
|
||||||
super(sessionFactory);
|
super(sessionFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Feed> findNextUpdatable(int count) {
|
public List<Feed> findNextUpdatable(int count, Date lastLoginThreshold) {
|
||||||
return query().selectFrom(feed)
|
JPAQuery<Feed> query = query().selectFrom(feed).where(feed.disabledUntil.isNull().or(feed.disabledUntil.lt(new Date())));
|
||||||
.where(feed.disabledUntil.isNull().or(feed.disabledUntil.lt(new Date())))
|
if (lastLoginThreshold != null) {
|
||||||
.orderBy(feed.disabledUntil.asc())
|
query.where(JPAExpressions.selectOne()
|
||||||
.limit(count)
|
.from(subscription)
|
||||||
.fetch();
|
.join(subscription.user)
|
||||||
|
.where(subscription.feed.id.eq(feed.id), subscription.user.lastLogin.gt(lastLoginThreshold))
|
||||||
|
.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.orderBy(feed.disabledUntil.asc()).limit(count).fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisabledUntil(List<Long> feedIds, Date date) {
|
public void setDisabledUntil(List<Long> feedIds, Date date) {
|
||||||
|
|||||||
@@ -86,10 +86,12 @@ public class FeedRefreshEngine implements Managed {
|
|||||||
Feed feed = queue.take();
|
Feed feed = queue.take();
|
||||||
|
|
||||||
// send the feed to be processed
|
// send the feed to be processed
|
||||||
|
log.debug("got feed {} from the queue, send it for processing", feed.getId());
|
||||||
processFeedAsync(feed);
|
processFeedAsync(feed);
|
||||||
|
|
||||||
// we removed a feed from the queue, try to refill it as it may now be empty
|
// we removed a feed from the queue, try to refill it as it may now be empty
|
||||||
if (queue.isEmpty()) {
|
if (queue.isEmpty()) {
|
||||||
|
log.debug("took the last feed from the queue, try to refill");
|
||||||
refillQueueAsync();
|
refillQueueAsync();
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -108,9 +110,11 @@ public class FeedRefreshEngine implements Managed {
|
|||||||
while (!refillLoopExecutor.isShutdown()) {
|
while (!refillLoopExecutor.isShutdown()) {
|
||||||
try {
|
try {
|
||||||
if (queue.isEmpty()) {
|
if (queue.isEmpty()) {
|
||||||
|
log.debug("refilling queue");
|
||||||
refillQueueAsync();
|
refillQueueAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.debug("sleeping for 15s");
|
||||||
TimeUnit.SECONDS.sleep(15);
|
TimeUnit.SECONDS.sleep(15);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
log.debug("interrupted while sleeping");
|
log.debug("interrupted while sleeping");
|
||||||
@@ -123,6 +127,7 @@ public class FeedRefreshEngine implements Managed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void refreshImmediately(Feed feed) {
|
public void refreshImmediately(Feed feed) {
|
||||||
|
log.debug("add feed {} at the start of the queue", feed.getId());
|
||||||
// remove the feed from the queue if it was already queued to avoid refreshing it twice
|
// remove the feed from the queue if it was already queued to avoid refreshing it twice
|
||||||
queue.removeIf(f -> f.getId().equals(feed.getId()));
|
queue.removeIf(f -> f.getId().equals(feed.getId()));
|
||||||
queue.addFirst(feed);
|
queue.addFirst(feed);
|
||||||
@@ -136,7 +141,9 @@ public class FeedRefreshEngine implements Managed {
|
|||||||
|
|
||||||
refill.mark();
|
refill.mark();
|
||||||
|
|
||||||
for (Feed feed : getNextUpdatableFeeds(getBatchSize())) {
|
List<Feed> nextUpdatableFeeds = getNextUpdatableFeeds(getBatchSize());
|
||||||
|
log.debug("found {} feeds that are up for refresh", nextUpdatableFeeds.size());
|
||||||
|
for (Feed feed : nextUpdatableFeeds) {
|
||||||
// add the feed only if it was not already queued
|
// add the feed only if it was not already queued
|
||||||
if (queue.stream().noneMatch(f -> f.getId().equals(feed.getId()))) {
|
if (queue.stream().noneMatch(f -> f.getId().equals(feed.getId()))) {
|
||||||
queue.addLast(feed);
|
queue.addLast(feed);
|
||||||
@@ -161,7 +168,10 @@ public class FeedRefreshEngine implements Managed {
|
|||||||
|
|
||||||
private List<Feed> getNextUpdatableFeeds(int max) {
|
private List<Feed> getNextUpdatableFeeds(int max) {
|
||||||
return unitOfWork.call(() -> {
|
return unitOfWork.call(() -> {
|
||||||
List<Feed> feeds = feedDAO.findNextUpdatable(max);
|
Date lastLoginThreshold = Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad())
|
||||||
|
? DateUtils.addDays(new Date(), -30)
|
||||||
|
: null;
|
||||||
|
List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold);
|
||||||
// update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable()
|
// update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable()
|
||||||
Date nextUpdateDate = DateUtils.addMinutes(new Date(), config.getApplicationSettings().getRefreshIntervalMinutes());
|
Date nextUpdateDate = DateUtils.addMinutes(new Date(), config.getApplicationSettings().getRefreshIntervalMinutes());
|
||||||
feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).collect(Collectors.toList()), nextUpdateDate);
|
feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).collect(Collectors.toList()), nextUpdateDate);
|
||||||
|
|||||||
@@ -38,6 +38,6 @@ public class FeedCategory extends AbstractModel {
|
|||||||
|
|
||||||
private boolean collapsed;
|
private boolean collapsed;
|
||||||
|
|
||||||
private Integer position;
|
private int position;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class FeedSubscription extends AbstractModel {
|
|||||||
@OneToMany(mappedBy = "subscription", cascade = CascadeType.REMOVE)
|
@OneToMany(mappedBy = "subscription", cascade = CascadeType.REMOVE)
|
||||||
private Set<FeedEntryStatus> statuses;
|
private Set<FeedEntryStatus> statuses;
|
||||||
|
|
||||||
private Integer position;
|
private int position;
|
||||||
|
|
||||||
@Column(name = "filtering_expression", length = 4096)
|
@Column(name = "filtering_expression", length = 4096)
|
||||||
private String filter;
|
private String filter;
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import javax.persistence.Table;
|
|||||||
import javax.persistence.Temporal;
|
import javax.persistence.Temporal;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@@ -49,17 +47,4 @@ public class User extends AbstractModel {
|
|||||||
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
private Date recoverPasswordTokenDate;
|
private Date recoverPasswordTokenDate;
|
||||||
|
|
||||||
@Column(name = "last_full_refresh")
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
|
||||||
private Date lastFullRefresh;
|
|
||||||
|
|
||||||
public boolean shouldRefreshFeedsAt(Date when) {
|
|
||||||
return lastFullRefresh == null || lastFullRefreshMoreThan30MinutesBefore(when);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean lastFullRefreshMoreThan30MinutesBefore(Date when) {
|
|
||||||
return lastFullRefresh.before(DateUtils.addMinutes(when, -30));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.commafeed.backend.service;
|
package com.commafeed.backend.service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -107,6 +108,17 @@ public class FeedSubscriptionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void refreshAllUpForRefresh(User user) {
|
||||||
|
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user);
|
||||||
|
for (FeedSubscription sub : subs) {
|
||||||
|
Date disabledUntil = sub.getFeed().getDisabledUntil();
|
||||||
|
if (disabledUntil == null || disabledUntil.before(new Date())) {
|
||||||
|
Feed feed = sub.getFeed();
|
||||||
|
feedRefreshEngine.refreshImmediately(feed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Long, UnreadCount> getUnreadCount(User user) {
|
public Map<Long, UnreadCount> getUnreadCount(User user) {
|
||||||
return feedSubscriptionDAO.findAll(user).stream().collect(Collectors.toMap(FeedSubscription::getId, s -> getUnreadCount(user, s)));
|
return feedSubscriptionDAO.findAll(user).stream().collect(Collectors.toMap(FeedSubscription::getId, s -> getUnreadCount(user, s)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,25 +25,20 @@ public class PostLoginActivities {
|
|||||||
private final CommaFeedConfiguration config;
|
private final CommaFeedConfiguration config;
|
||||||
|
|
||||||
public void executeFor(User user) {
|
public void executeFor(User user) {
|
||||||
Date lastLogin = user.getLastLogin();
|
// only update lastLogin every once in a while in order to avoid invalidating the cache every time someone logs in
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
|
Date lastLogin = user.getLastLogin();
|
||||||
boolean saveUser = false;
|
if (lastLogin == null || lastLogin.before(DateUtils.addMinutes(now, -30))) {
|
||||||
|
|
||||||
// only update lastLogin field every hour in order to not
|
|
||||||
// invalidate the cache every time someone logs in
|
|
||||||
if (lastLogin == null || lastLogin.before(DateUtils.addHours(now, -1))) {
|
|
||||||
user.setLastLogin(now);
|
user.setLastLogin(now);
|
||||||
saveUser = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad()) && user.shouldRefreshFeedsAt(now)) {
|
boolean heavyLoad = Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad());
|
||||||
feedSubscriptionService.refreshAll(user);
|
if (heavyLoad) {
|
||||||
user.setLastFullRefresh(now);
|
// the amount of feeds in the database that are up for refresh might be very large since we're in heavy load mode
|
||||||
saveUser = true;
|
// the feed refresh engine might not be able to catch up quickly enough
|
||||||
}
|
// put feeds from online users that are up for refresh at the top of the queue
|
||||||
|
feedSubscriptionService.refreshAllUpForRefresh(user);
|
||||||
|
}
|
||||||
|
|
||||||
if (saveUser) {
|
|
||||||
// Post login activites are susceptible to run for any webservice call.
|
// Post login activites are susceptible to run for any webservice call.
|
||||||
// We update the user in a new transaction to update the user immediately.
|
// We update the user in a new transaction to update the user immediately.
|
||||||
// If we didn't and the webservice call takes time, subsequent webservice calls would have to wait for the first call to
|
// If we didn't and the webservice call takes time, subsequent webservice calls would have to wait for the first call to
|
||||||
@@ -51,5 +46,4 @@ public class PostLoginActivities {
|
|||||||
unitOfWork.run(() -> userDAO.saveOrUpdate(user));
|
unitOfWork.run(() -> userDAO.saveOrUpdate(user));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,5 +35,5 @@ public class Category implements Serializable {
|
|||||||
private boolean expanded;
|
private boolean expanded;
|
||||||
|
|
||||||
@ApiModelProperty(value = "position of the category in the list", required = true)
|
@ApiModelProperty(value = "position of the category in the list", required = true)
|
||||||
private Integer position;
|
private int position;
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ public class Subscription implements Serializable {
|
|||||||
private String categoryId;
|
private String categoryId;
|
||||||
|
|
||||||
@ApiModelProperty("position of the subscription's in the list")
|
@ApiModelProperty("position of the subscription's in the list")
|
||||||
private Integer position;
|
private int position;
|
||||||
|
|
||||||
@ApiModelProperty(value = "date of the newest item", dataType = "number")
|
@ApiModelProperty(value = "date of the newest item", dataType = "number")
|
||||||
private Date newestItemTime;
|
private Date newestItemTime;
|
||||||
|
|||||||
@@ -458,7 +458,7 @@ public class CategoryREST {
|
|||||||
category.getChildren().add(child);
|
category.getChildren().add(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(category.getChildren(), (o1, o2) -> ObjectUtils.compare(o1.getPosition(), o2.getPosition()));
|
category.getChildren().sort(Comparator.comparing(Category::getPosition).thenComparing(Category::getName));
|
||||||
|
|
||||||
for (FeedSubscription subscription : subscriptions) {
|
for (FeedSubscription subscription : subscriptions) {
|
||||||
if (id == null && subscription.getCategory() == null
|
if (id == null && subscription.getCategory() == null
|
||||||
@@ -468,7 +468,7 @@ public class CategoryREST {
|
|||||||
category.getFeeds().add(sub);
|
category.getFeeds().add(sub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(category.getFeeds(), (o1, o2) -> ObjectUtils.compare(o1.getPosition(), o2.getPosition()));
|
category.getFeeds().sort(Comparator.comparing(Subscription::getPosition).thenComparing(Subscription::getName));
|
||||||
|
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.commafeed.frontend.servlet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class RobotsTxtDisallowAllServlet extends HttpServlet {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
|
resp.setContentType("text/plain");
|
||||||
|
resp.getWriter().write("User-agent: *");
|
||||||
|
resp.getWriter().write("\n");
|
||||||
|
resp.getWriter().write("Disallow: /");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||||
|
|
||||||
|
|
||||||
|
<changeSet id="position-required" author="athou">
|
||||||
|
<update tableName="FEEDCATEGORIES">
|
||||||
|
<column name="position" valueNumeric="0" />
|
||||||
|
<where>position is null</where>
|
||||||
|
</update>
|
||||||
|
<addNotNullConstraint tableName="FEEDCATEGORIES" columnName="position" columnDataType="int" />
|
||||||
|
|
||||||
|
<update tableName="FEEDSUBSCRIPTIONS">
|
||||||
|
<column name="position" valueNumeric="0" />
|
||||||
|
<where>position is null</where>
|
||||||
|
</update>
|
||||||
|
<addNotNullConstraint tableName="FEEDSUBSCRIPTIONS" columnName="position" columnDataType="int" />
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
<changeSet id="drop-unused-last-full-refresh" author="athou">
|
||||||
|
<dropColumn tableName="USERS" columnName="last_full_refresh" />
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
</databaseChangeLog>
|
||||||
@@ -19,5 +19,6 @@
|
|||||||
<include file="changelogs/db.changelog-2.6.xml" />
|
<include file="changelogs/db.changelog-2.6.xml" />
|
||||||
<include file="changelogs/db.changelog-3.2.xml" />
|
<include file="changelogs/db.changelog-3.2.xml" />
|
||||||
<include file="changelogs/db.changelog-3.5.xml" />
|
<include file="changelogs/db.changelog-3.5.xml" />
|
||||||
|
<include file="changelogs/db.changelog-3.6.xml" />
|
||||||
|
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
@@ -3,6 +3,9 @@
|
|||||||
app:
|
app:
|
||||||
# url used to access commafeed
|
# url used to access commafeed
|
||||||
publicUrl: http://localhost:8082/
|
publicUrl: http://localhost:8082/
|
||||||
|
|
||||||
|
# whether to expose a robots.txt file that disallows web crawlers and search engine indexers
|
||||||
|
hideFromWebCrawlers: true
|
||||||
|
|
||||||
# whether to allow user registrations
|
# whether to allow user registrations
|
||||||
allowRegistrations: true
|
allowRegistrations: true
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed</artifactId>
|
<artifactId>commafeed</artifactId>
|
||||||
<version>3.6.0</version>
|
<version>3.7.0</version>
|
||||||
<name>CommaFeed</name>
|
<name>CommaFeed</name>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ if [[ "$BRANCH" != "master" ]]; then
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# make sure README.md has been updated
|
# make sure CHANGELOG.md has been updated
|
||||||
read -r -p "Has README.md been updated? (Y/n) " CONFIRM
|
read -r -p "Has CHANGELOG.md been updated? (Y/n) " CONFIRM
|
||||||
case "$CONFIRM" in
|
case "$CONFIRM" in
|
||||||
n | N) exit ;;
|
n | N) exit ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
Reference in New Issue
Block a user