feat(mobile): translation for home tabs (#3386)
* feat(mobile): translation content * Starred * inbox feeds lists * profile * discovery category * search * dayjs * bring localizations back * translation for mobile content * todo note * add settings resource * settings * Extract * Extract * Manually type * extend * remove feed_view_type * remove discover.category * update note * type
This commit is contained in:
parent
e7ae1f69ad
commit
20f0abe302
|
|
@ -39,7 +39,7 @@ export const RecommendationCard: FC<RecommendationCardProps> = memo(
|
|||
categories.delete("popular")
|
||||
return {
|
||||
maintainers: Array.from(maintainers),
|
||||
categories: Array.from(categories) as typeof RSSHubCategories | string[],
|
||||
categories: Array.from(categories) as unknown as typeof RSSHubCategories,
|
||||
}
|
||||
}, [data])
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ export const RecommendationCard: FC<RecommendationCardProps> = memo(
|
|||
)}
|
||||
>
|
||||
{RSSHubCategories.includes(c)
|
||||
? t(`discover.category.${c as (typeof RSSHubCategories)[number]}`)
|
||||
? t(`discover.category.${c}`, { ns: "common" })
|
||||
: upperFirst(c)}
|
||||
</button>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ export function Recommendations({
|
|||
<TabsList>
|
||||
{RSSHubCategories.map((category) => (
|
||||
<TabsTrigger data-value={category} key={category} value={category}>
|
||||
{t(`discover.category.${category}`)}
|
||||
{t(`discover.category.${category}`, { ns: "common" })}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export const ViewSelectContent = () => {
|
|||
<SelectItem key={view.name} value={`${index}`}>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={cn(view.className, "flex")}>{view.icon}</span>
|
||||
<span>{t(view.name as any)}</span>
|
||||
<span>{t(view.name, { ns: "common" })}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,9 @@ export const SettingLists = () => {
|
|||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>{t(views[row.view]!.name as any)}</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t(views[row.view]!.name, { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,9 @@ export const ViewSelectorRadioGroup = forwardRef<
|
|||
{cloneElement(view.icon, {
|
||||
className: `text-lg ${view.icon?.props?.className ?? ""}`,
|
||||
})}
|
||||
<span className="mt-1 hidden text-xs lg:inline">{t(view.name as any)}</span>
|
||||
<span className="mt-1 hidden text-xs lg:inline">
|
||||
{t(view.name, { ns: "common" })}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ function FeedCategoryImpl({ data: ids, view, categoryOpenStateData }: FeedCatego
|
|||
submenu: views
|
||||
.filter((v) => v.view !== view)
|
||||
.map((v) => ({
|
||||
label: t(v.name as any),
|
||||
label: t(v.name, { ns: "common" }),
|
||||
type: "text" as const,
|
||||
shortcut: (v.view + 1).toString(),
|
||||
icon: v.icon,
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ const FeedListImpl = ({ className, view }: { className?: string; view: number })
|
|||
<span className="ml-2">
|
||||
{t("words.all", { ns: "common" })}
|
||||
{t("space", { ns: "common" })}
|
||||
{t(views[view]!.name as any)}
|
||||
{t(views[view]!.name, { ns: "common" })}
|
||||
</span>
|
||||
</button>
|
||||
<SortableFeedList
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export const ListHeader = ({ view }: { view: number }) => {
|
|||
}
|
||||
}}
|
||||
>
|
||||
{view !== undefined && t(views[view]!.name as any)}
|
||||
{view !== undefined && t(views[view]!.name, { ns: "common" })}
|
||||
</div>
|
||||
<div className="lg:!text-theme-vibrancyFg ml-2 flex items-center gap-3 text-base text-zinc-400 lg:text-sm dark:text-zinc-600">
|
||||
<SortButton />
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ const ViewSwitchButton: FC<{
|
|||
<ActionButton
|
||||
ref={setNodeRef}
|
||||
key={item.name}
|
||||
tooltip={t(item.name as any)}
|
||||
tooltip={t(item.name, { ns: "common" })}
|
||||
shortcut={`${view + 1}`}
|
||||
className={cn(
|
||||
isActive && item.className,
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ export const useFeedHeaderTitle = () => {
|
|||
|
||||
switch (currentFeedId) {
|
||||
case ROUTE_FEED_PENDING: {
|
||||
return t(views[view]!.name as any)
|
||||
return t(views[view]!.name, { ns: "common" })
|
||||
}
|
||||
case FEED_COLLECTION_LIST: {
|
||||
return t("words.starred")
|
||||
|
|
|
|||
|
|
@ -51,7 +51,28 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
|
|||
LSApplicationQueriesSchemes: ["bilibili", "youtube"],
|
||||
CFBundleAllowMixedLocalizations: true,
|
||||
// apps/mobile/src/@types/constants.ts currentSupportedLanguages
|
||||
CFBundleLocalizations: ["en", "zh-CN"],
|
||||
CFBundleLocalizations: [
|
||||
"en",
|
||||
"de",
|
||||
"ja",
|
||||
"zh-CN",
|
||||
"zh-TW",
|
||||
"zh-HK",
|
||||
"pt",
|
||||
"fr",
|
||||
"ar-DZ",
|
||||
"ar-SA",
|
||||
"ar-MA",
|
||||
"ar-IQ",
|
||||
"ar-KW",
|
||||
"ar-TN",
|
||||
"fi",
|
||||
"it",
|
||||
"ru",
|
||||
"es",
|
||||
"ko",
|
||||
"tr",
|
||||
],
|
||||
CFBundleDevelopmentRegion: "en",
|
||||
},
|
||||
googleServicesFile: "./build/GoogleService-Info.plist",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,50 @@
|
|||
const langs = ["en", "zh-CN"] as const
|
||||
const langs = [
|
||||
"en",
|
||||
"de",
|
||||
"ja",
|
||||
"zh-CN",
|
||||
"zh-TW",
|
||||
"zh-HK",
|
||||
"pt",
|
||||
"fr",
|
||||
"ar-DZ",
|
||||
"ar-SA",
|
||||
"ar-MA",
|
||||
"ar-IQ",
|
||||
"ar-KW",
|
||||
"ar-TN",
|
||||
"fi",
|
||||
"it",
|
||||
"ru",
|
||||
"es",
|
||||
"ko",
|
||||
"tr",
|
||||
] as const
|
||||
export const currentSupportedLanguages = langs as readonly string[]
|
||||
export type MobileSupportedLanguages = (typeof langs)[number]
|
||||
|
||||
export const ns = ["default", "common", "lang", "errors"] as const
|
||||
export const ns = ["default", "common", "lang", "errors", "settings"] as const
|
||||
export const defaultNS = "default" as const
|
||||
|
||||
export const dayjsLocaleImportMap = {
|
||||
en: ["en", () => import("dayjs/locale/en")],
|
||||
["zh-CN"]: ["zh-cn", () => import("dayjs/locale/zh-cn")],
|
||||
["ja"]: ["ja", () => import("dayjs/locale/ja")],
|
||||
["ru"]: ["ru", () => import("dayjs/locale/ru")],
|
||||
["fi"]: ["fi", () => import("dayjs/locale/fi")],
|
||||
["it"]: ["it", () => import("dayjs/locale/it")],
|
||||
["ar-DZ"]: ["ar-dz", () => import("dayjs/locale/ar-dz")],
|
||||
["ar-SA"]: ["ar-sa", () => import("dayjs/locale/ar-sa")],
|
||||
["ar-MA"]: ["ar-ma", () => import("dayjs/locale/ar-ma")],
|
||||
["es"]: ["es", () => import("dayjs/locale/es")],
|
||||
["fr"]: ["fr", () => import("dayjs/locale/fr")],
|
||||
["pt"]: ["pt", () => import("dayjs/locale/pt")],
|
||||
["zh-TW"]: ["zh-tw", () => import("dayjs/locale/zh-tw")],
|
||||
["ar-IQ"]: ["ar-iq", () => import("dayjs/locale/ar-iq")],
|
||||
["ar-KW"]: ["ar-kw", () => import("dayjs/locale/ar-kw")],
|
||||
["ar-TN"]: ["ar-tn", () => import("dayjs/locale/ar-tn")],
|
||||
["zh-HK"]: ["zh-hk", () => import("dayjs/locale/zh-hk")],
|
||||
["de"]: ["de", () => import("dayjs/locale/de")],
|
||||
["ko"]: ["ko", () => import("dayjs/locale/ko")],
|
||||
["tr"]: ["tr", () => import("dayjs/locale/tr")],
|
||||
} as const
|
||||
|
|
|
|||
|
|
@ -1,26 +1,249 @@
|
|||
import common_ardz from "@locales/common/ar-DZ.json"
|
||||
import common_ariq from "@locales/common/ar-IQ.json"
|
||||
import common_arkw from "@locales/common/ar-KW.json"
|
||||
import common_arma from "@locales/common/ar-MA.json"
|
||||
import common_arsa from "@locales/common/ar-SA.json"
|
||||
import common_artn from "@locales/common/ar-TN.json"
|
||||
import common_de from "@locales/common/de.json"
|
||||
import common_en from "@locales/common/en.json"
|
||||
import common_es from "@locales/common/es.json"
|
||||
import common_fi from "@locales/common/fi.json"
|
||||
import common_fr from "@locales/common/fr.json"
|
||||
import common_it from "@locales/common/it.json"
|
||||
import common_ja from "@locales/common/ja.json"
|
||||
import common_ko from "@locales/common/ko.json"
|
||||
import common_pt from "@locales/common/pt.json"
|
||||
import common_ru from "@locales/common/ru.json"
|
||||
import common_tr from "@locales/common/tr.json"
|
||||
import common_zhCN from "@locales/common/zh-CN.json"
|
||||
import common_zhHK from "@locales/common/zh-HK.json"
|
||||
import common_zhTW from "@locales/common/zh-TW.json"
|
||||
import errors_de from "@locales/errors/de.json"
|
||||
import errors_en from "@locales/errors/en.json"
|
||||
import errors_fr from "@locales/errors/fr.json"
|
||||
import errors_ja from "@locales/errors/ja.json"
|
||||
import errors_ko from "@locales/errors/ko.json"
|
||||
import errors_ru from "@locales/errors/ru.json"
|
||||
import errors_tr from "@locales/errors/tr.json"
|
||||
import errors_zhCN from "@locales/errors/zh-CN.json"
|
||||
import errors_zhHK from "@locales/errors/zh-HK.json"
|
||||
import errors_zhTW from "@locales/errors/zh-TW.json"
|
||||
import lang_ardz from "@locales/lang/ar-DZ.json"
|
||||
import lang_ariq from "@locales/lang/ar-IQ.json"
|
||||
import lang_arkw from "@locales/lang/ar-KW.json"
|
||||
import lang_arma from "@locales/lang/ar-MA.json"
|
||||
import lang_arsa from "@locales/lang/ar-SA.json"
|
||||
import lang_artn from "@locales/lang/ar-TN.json"
|
||||
import lang_de from "@locales/lang/de.json"
|
||||
import lang_en from "@locales/lang/en.json"
|
||||
import lang_es from "@locales/lang/es.json"
|
||||
import lang_fi from "@locales/lang/fi.json"
|
||||
import lang_fr from "@locales/lang/fr.json"
|
||||
import lang_it from "@locales/lang/it.json"
|
||||
import lang_ja from "@locales/lang/ja.json"
|
||||
import lang_ko from "@locales/lang/ko.json"
|
||||
import lang_pt from "@locales/lang/pt.json"
|
||||
import lang_ru from "@locales/lang/ru.json"
|
||||
import lang_tr from "@locales/lang/tr.json"
|
||||
import lang_zhCN from "@locales/lang/zh-CN.json"
|
||||
import lang_zhHK from "@locales/lang/zh-HK.json"
|
||||
import lang_zhTW from "@locales/lang/zh-TW.json"
|
||||
import arDZ from "@locales/mobile/default/ar-DZ.json"
|
||||
import arIQ from "@locales/mobile/default/ar-IQ.json"
|
||||
import arKW from "@locales/mobile/default/ar-KW.json"
|
||||
import arMA from "@locales/mobile/default/ar-MA.json"
|
||||
import arSA from "@locales/mobile/default/ar-SA.json"
|
||||
import arTN from "@locales/mobile/default/ar-TN.json"
|
||||
import de from "@locales/mobile/default/de.json"
|
||||
import en from "@locales/mobile/default/en.json"
|
||||
import es from "@locales/mobile/default/es.json"
|
||||
import fi from "@locales/mobile/default/fi.json"
|
||||
import fr from "@locales/mobile/default/fr.json"
|
||||
import it from "@locales/mobile/default/it.json"
|
||||
import ja from "@locales/mobile/default/ja.json"
|
||||
import ko from "@locales/mobile/default/ko.json"
|
||||
import pt from "@locales/mobile/default/pt.json"
|
||||
import ru from "@locales/mobile/default/ru.json"
|
||||
import tr from "@locales/mobile/default/tr.json"
|
||||
import zhCN from "@locales/mobile/default/zh-CN.json"
|
||||
import zhHK from "@locales/mobile/default/zh-HK.json"
|
||||
import zhTW from "@locales/mobile/default/zh-TW.json"
|
||||
import settings_ardz from "@locales/settings/ar-DZ.json"
|
||||
import settings_ariq from "@locales/settings/ar-IQ.json"
|
||||
import settings_arkw from "@locales/settings/ar-KW.json"
|
||||
import settings_arma from "@locales/settings/ar-MA.json"
|
||||
import settings_arsa from "@locales/settings/ar-SA.json"
|
||||
import settings_artn from "@locales/settings/ar-TN.json"
|
||||
import settings_de from "@locales/settings/de.json"
|
||||
import settings_en from "@locales/settings/en.json"
|
||||
import settings_es from "@locales/settings/es.json"
|
||||
import settings_fi from "@locales/settings/fi.json"
|
||||
import settings_fr from "@locales/settings/fr.json"
|
||||
import settings_it from "@locales/settings/it.json"
|
||||
import settings_ja from "@locales/settings/ja.json"
|
||||
import settings_ko from "@locales/settings/ko.json"
|
||||
import settings_pt from "@locales/settings/pt.json"
|
||||
import settings_ru from "@locales/settings/ru.json"
|
||||
import settings_tr from "@locales/settings/tr.json"
|
||||
import settings_zhCN from "@locales/settings/zh-CN.json"
|
||||
import settings_zhHK from "@locales/settings/zh-HK.json"
|
||||
import settings_zhTW from "@locales/settings/zh-TW.json"
|
||||
|
||||
import type { MobileSupportedLanguages, ns } from "./constants"
|
||||
|
||||
// @keep-sorted
|
||||
export const defaultResources = {
|
||||
// @keep-sorted
|
||||
"ar-DZ": {
|
||||
common: common_ardz,
|
||||
default: arDZ,
|
||||
lang: lang_ardz,
|
||||
settings: settings_ardz,
|
||||
},
|
||||
// @keep-sorted
|
||||
"ar-IQ": {
|
||||
common: common_ariq,
|
||||
default: arIQ,
|
||||
lang: lang_ariq,
|
||||
settings: settings_ariq,
|
||||
},
|
||||
// @keep-sorted
|
||||
"ar-KW": {
|
||||
common: common_arkw,
|
||||
default: arKW,
|
||||
lang: lang_arkw,
|
||||
settings: settings_arkw,
|
||||
},
|
||||
// @keep-sorted
|
||||
"ar-MA": {
|
||||
common: common_arma,
|
||||
default: arMA,
|
||||
lang: lang_arma,
|
||||
settings: settings_arma,
|
||||
},
|
||||
// @keep-sorted
|
||||
"ar-SA": {
|
||||
common: common_arsa,
|
||||
default: arSA,
|
||||
lang: lang_arsa,
|
||||
settings: settings_arsa,
|
||||
},
|
||||
// @keep-sorted
|
||||
"ar-TN": {
|
||||
common: common_artn,
|
||||
default: arTN,
|
||||
lang: lang_artn,
|
||||
settings: settings_artn,
|
||||
},
|
||||
// @keep-sorted
|
||||
"zh-CN": {
|
||||
default: zhCN,
|
||||
common: common_zhCN,
|
||||
default: zhCN,
|
||||
errors: errors_zhCN,
|
||||
lang: lang_zhCN,
|
||||
settings: settings_zhCN,
|
||||
},
|
||||
// @keep-sorted
|
||||
"zh-HK": {
|
||||
common: common_zhHK,
|
||||
default: zhHK,
|
||||
errors: errors_zhHK,
|
||||
lang: lang_zhHK,
|
||||
settings: settings_zhHK,
|
||||
},
|
||||
// @keep-sorted
|
||||
"zh-TW": {
|
||||
common: common_zhTW,
|
||||
default: zhTW,
|
||||
errors: errors_zhTW,
|
||||
lang: lang_zhTW,
|
||||
settings: settings_zhTW,
|
||||
},
|
||||
// @keep-sorted
|
||||
de: {
|
||||
common: common_de,
|
||||
default: de,
|
||||
errors: errors_de,
|
||||
lang: lang_de,
|
||||
settings: settings_de,
|
||||
},
|
||||
// @keep-sorted
|
||||
en: {
|
||||
default: en,
|
||||
common: common_en,
|
||||
default: en,
|
||||
errors: errors_en,
|
||||
lang: lang_en,
|
||||
settings: settings_en,
|
||||
},
|
||||
} satisfies Record<MobileSupportedLanguages, Record<(typeof ns)[number], Record<string, string>>>
|
||||
// @keep-sorted
|
||||
es: {
|
||||
common: common_es,
|
||||
default: es,
|
||||
lang: lang_es,
|
||||
settings: settings_es,
|
||||
},
|
||||
// @keep-sorted
|
||||
fi: {
|
||||
common: common_fi,
|
||||
default: fi,
|
||||
lang: lang_fi,
|
||||
settings: settings_fi,
|
||||
},
|
||||
// @keep-sorted
|
||||
fr: {
|
||||
common: common_fr,
|
||||
default: fr,
|
||||
errors: errors_fr,
|
||||
lang: lang_fr,
|
||||
settings: settings_fr,
|
||||
},
|
||||
// @keep-sorted
|
||||
it: {
|
||||
common: common_it,
|
||||
default: it,
|
||||
lang: lang_it,
|
||||
settings: settings_it,
|
||||
},
|
||||
// @keep-sorted
|
||||
ja: {
|
||||
common: common_ja,
|
||||
default: ja,
|
||||
errors: errors_ja,
|
||||
lang: lang_ja,
|
||||
settings: settings_ja,
|
||||
},
|
||||
// @keep-sorted
|
||||
ko: {
|
||||
common: common_ko,
|
||||
default: ko,
|
||||
errors: errors_ko,
|
||||
lang: lang_ko,
|
||||
settings: settings_ko,
|
||||
},
|
||||
// @keep-sorted
|
||||
pt: {
|
||||
common: common_pt,
|
||||
default: pt,
|
||||
lang: lang_pt,
|
||||
settings: settings_pt,
|
||||
},
|
||||
// @keep-sorted
|
||||
ru: {
|
||||
common: common_ru,
|
||||
default: ru,
|
||||
errors: errors_ru,
|
||||
lang: lang_ru,
|
||||
settings: settings_ru,
|
||||
},
|
||||
// @keep-sorted
|
||||
tr: {
|
||||
common: common_tr,
|
||||
default: tr,
|
||||
errors: errors_tr,
|
||||
lang: lang_tr,
|
||||
settings: settings_tr,
|
||||
},
|
||||
} satisfies Record<
|
||||
MobileSupportedLanguages,
|
||||
Partial<Record<(typeof ns)[number], Record<string, string>>>
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import dayjs from "dayjs"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import type { TextProps } from "react-native"
|
||||
import { Pressable } from "react-native"
|
||||
import Animated, { FadeOut } from "react-native-reanimated"
|
||||
|
|
@ -49,9 +50,10 @@ export const RelativeDateTime = ({
|
|||
date,
|
||||
displayAbsoluteTimeAfterDay,
|
||||
dateFormatTemplate,
|
||||
postfixText = "ago",
|
||||
postfixText,
|
||||
...props
|
||||
}: RelativeDateTimeProps) => {
|
||||
const { t } = useTranslation("common")
|
||||
const [relative, setRelative] = useState<string>(() =>
|
||||
formatTime(date, displayAbsoluteTimeAfterDay, dateFormatTemplate),
|
||||
)
|
||||
|
|
@ -80,7 +82,9 @@ export const RelativeDateTime = ({
|
|||
}}
|
||||
>
|
||||
<Animated.Text {...props} key={mode} exiting={FadeOut}>
|
||||
{mode === "relative" ? `${relative} ${postfixText}` : memoizedFormatTime}
|
||||
{mode === "relative"
|
||||
? `${relative}${t("space")}${postfixText ?? t("words.ago")}`
|
||||
: memoizedFormatTime}
|
||||
</Animated.Text>
|
||||
</Pressable>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { FeedViewType } from "@follow/constants"
|
||||
import type * as React from "react"
|
||||
import type { ViewDefinition as ViewDefinitionBase } from "@follow/constants"
|
||||
import { FeedViewType, views as viewsBase } from "@follow/constants"
|
||||
import colors from "tailwindcss/colors"
|
||||
|
||||
import { AnnouncementCuteFiIcon } from "../icons/announcement_cute_fi"
|
||||
|
|
@ -10,56 +10,43 @@ import { TwitterCuteFiIcon } from "../icons/twitter_cute_fi"
|
|||
import { VideoCuteFiIcon } from "../icons/video_cute_fi"
|
||||
import { accentColor } from "../theme/colors"
|
||||
|
||||
export interface ViewDefinition {
|
||||
name: string
|
||||
interface ViewDefinitionExtended {
|
||||
icon: React.FC<{ color?: string; height?: number; width?: number }>
|
||||
activeColor: string
|
||||
translation: string
|
||||
view: FeedViewType
|
||||
wideMode?: boolean
|
||||
gridMode?: boolean
|
||||
}
|
||||
export const views: ViewDefinition[] = [
|
||||
{
|
||||
name: "Articles",
|
||||
const extendMap: Record<FeedViewType, ViewDefinitionExtended> = {
|
||||
[FeedViewType.Articles]: {
|
||||
icon: PaperCuteFiIcon,
|
||||
activeColor: accentColor,
|
||||
translation: "title,description",
|
||||
view: FeedViewType.Articles,
|
||||
},
|
||||
{
|
||||
name: "Social Media",
|
||||
[FeedViewType.SocialMedia]: {
|
||||
icon: TwitterCuteFiIcon,
|
||||
activeColor: colors.sky[500],
|
||||
translation: "content",
|
||||
view: FeedViewType.SocialMedia,
|
||||
},
|
||||
{
|
||||
name: "Pictures",
|
||||
[FeedViewType.Pictures]: {
|
||||
icon: PicCuteFiIcon,
|
||||
activeColor: colors.green[500],
|
||||
translation: "title",
|
||||
view: FeedViewType.Pictures,
|
||||
},
|
||||
{
|
||||
name: "Videos",
|
||||
[FeedViewType.Videos]: {
|
||||
icon: VideoCuteFiIcon,
|
||||
activeColor: colors.red[500],
|
||||
translation: "title",
|
||||
view: FeedViewType.Videos,
|
||||
},
|
||||
{
|
||||
name: "Audios",
|
||||
[FeedViewType.Audios]: {
|
||||
icon: MicCuteFiIcon,
|
||||
activeColor: colors.purple[500],
|
||||
translation: "title",
|
||||
view: FeedViewType.Audios,
|
||||
},
|
||||
{
|
||||
name: "Notifications",
|
||||
[FeedViewType.Notifications]: {
|
||||
icon: AnnouncementCuteFiIcon,
|
||||
activeColor: colors.yellow[500],
|
||||
translation: "title",
|
||||
view: FeedViewType.Notifications,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
export interface ViewDefinition extends Omit<ViewDefinitionBase, "icon">, ViewDefinitionExtended {}
|
||||
|
||||
export const views: ViewDefinition[] = viewsBase.map((view) => {
|
||||
const extendedView = extendMap[view.view]
|
||||
return {
|
||||
...view,
|
||||
...extendedView,
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,27 +1,46 @@
|
|||
import dayjs from "dayjs"
|
||||
import { getLocales } from "expo-localization"
|
||||
import i18n from "i18next"
|
||||
import { initReactI18next } from "react-i18next"
|
||||
|
||||
import { currentSupportedLanguages, defaultNS, ns } from "@/src/@types/constants"
|
||||
import {
|
||||
currentSupportedLanguages,
|
||||
dayjsLocaleImportMap,
|
||||
defaultNS,
|
||||
ns,
|
||||
} from "@/src/@types/constants"
|
||||
import { defaultResources } from "@/src/@types/default-resource"
|
||||
|
||||
import { getGeneralSettings } from "../atoms/settings/general"
|
||||
|
||||
const fallbackLanguage = "en"
|
||||
|
||||
export const updateDayjsLocale = async (lang: string) => {
|
||||
if (!(lang in dayjsLocaleImportMap)) return
|
||||
const dayjsImport = dayjsLocaleImportMap[lang as keyof typeof dayjsLocaleImportMap]
|
||||
const [locale, loader] = dayjsImport
|
||||
await loader()
|
||||
dayjs.locale(locale)
|
||||
}
|
||||
|
||||
export async function initializeI18n() {
|
||||
return i18n.use(initReactI18next).init({
|
||||
ns,
|
||||
defaultNS,
|
||||
resources: defaultResources,
|
||||
const { language } = getGeneralSettings()
|
||||
|
||||
lng: getGeneralSettings().language,
|
||||
fallbackLng: fallbackLanguage,
|
||||
return Promise.all([
|
||||
updateDayjsLocale(language),
|
||||
i18n.use(initReactI18next).init({
|
||||
ns,
|
||||
defaultNS,
|
||||
resources: defaultResources,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
})
|
||||
lng: language,
|
||||
fallbackLng: fallbackLanguage,
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
export function getDeviceLanguage() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { RSSHubCategories } from "@follow/constants"
|
|||
import type { RSSHubRouteDeclaration } from "@follow/models/src/rsshub"
|
||||
import type { FC } from "react"
|
||||
import { memo, useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Clipboard, Text, TouchableOpacity, View } from "react-native"
|
||||
import WebView from "react-native-webview"
|
||||
import * as ContextMenu from "zeego/context-menu"
|
||||
|
|
@ -13,12 +14,11 @@ import { useNavigation } from "@/src/lib/navigation/hooks"
|
|||
import { toast } from "@/src/lib/toast"
|
||||
import { RsshubFormScreen } from "@/src/screens/(modal)/rsshub-form"
|
||||
|
||||
import { RSSHubCategoryCopyMap } from "./copy"
|
||||
|
||||
export const RecommendationListItem: FC<{
|
||||
data: RSSHubRouteDeclaration
|
||||
routePrefix: string
|
||||
}> = memo(({ data, routePrefix }) => {
|
||||
const { t } = useTranslation("common")
|
||||
const { maintainers, categories } = useMemo(() => {
|
||||
const maintainers = new Set<string>()
|
||||
const categories = new Set<string>()
|
||||
|
|
@ -34,7 +34,7 @@ export const RecommendationListItem: FC<{
|
|||
categories.delete("popular")
|
||||
return {
|
||||
maintainers: Array.from(maintainers),
|
||||
categories: Array.from(categories) as typeof RSSHubCategories | string[],
|
||||
categories: Array.from(categories) as unknown as typeof RSSHubCategories,
|
||||
}
|
||||
}, [data])
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ export const RecommendationListItem: FC<{
|
|||
key={c}
|
||||
>
|
||||
<Text className="text-text/60 text-xs" numberOfLines={1}>
|
||||
{RSSHubCategoryCopyMap[c as keyof typeof RSSHubCategoryCopyMap]}
|
||||
{t(`discover.category.${c}`)}
|
||||
</Text>
|
||||
</View>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { useQuery } from "@tanstack/react-query"
|
|||
import { useAtomValue } from "jotai"
|
||||
import type { FC } from "react"
|
||||
import { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import type { ScrollView } from "react-native"
|
||||
import {
|
||||
ActivityIndicator,
|
||||
|
|
@ -26,11 +27,11 @@ import {
|
|||
import type { TabComponent } from "@/src/components/ui/tabview/TabView"
|
||||
import { apiClient } from "@/src/lib/api-fetch"
|
||||
|
||||
import { RSSHubCategoryCopyMap } from "./copy"
|
||||
import { DiscoverContext } from "./DiscoverContext"
|
||||
import { RecommendationListItem } from "./RecommendationListItem"
|
||||
|
||||
export const Recommendations = () => {
|
||||
const { t } = useTranslation("common")
|
||||
const { animatedX, currentTabAtom } = useContext(DiscoverContext)
|
||||
const currentTab = useAtomValue(currentTabAtom)
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ export const Recommendations = () => {
|
|||
{loadedTabIndex.has(index) && (
|
||||
<Tab
|
||||
key={category}
|
||||
tab={{ name: RSSHubCategoryCopyMap[category], value: category }}
|
||||
tab={{ name: t(`discover.category.${category}`), value: category }}
|
||||
isSelected={currentTab === index}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
export const RSSHubCategoryCopyMap = {
|
||||
all: "All",
|
||||
anime: "ACG",
|
||||
bbs: "BBS",
|
||||
blog: "Blog",
|
||||
design: "Design",
|
||||
finance: "Finance",
|
||||
forecast: "Forecast",
|
||||
game: "Gaming",
|
||||
government: "Government",
|
||||
journal: "Scientific Journal",
|
||||
live: "Live",
|
||||
multimedia: "Multimedia",
|
||||
"new-media": "New Media",
|
||||
picture: "Picture",
|
||||
"program-update": "Application Updates",
|
||||
programming: "Programming",
|
||||
reading: "Reading",
|
||||
shopping: "Shopping",
|
||||
"social-media": "Social Media",
|
||||
study: "Study",
|
||||
"traditional-media": "News",
|
||||
travel: "Travel",
|
||||
university: "University",
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import { RSSHubCategories } from "@follow/constants"
|
|||
import { useAtom, useAtomValue, useSetAtom } from "jotai"
|
||||
import type { FC } from "react"
|
||||
import { useContext, useEffect, useRef, useState } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import type { Animated as RnAnimated, LayoutChangeEvent } from "react-native"
|
||||
import { Pressable, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native"
|
||||
import Animated, {
|
||||
|
|
@ -22,7 +23,6 @@ import SearchScreen from "@/src/screens/(headless)/search"
|
|||
import { accentColor, useColor } from "@/src/theme/colors"
|
||||
|
||||
import { AddFeedButton } from "../screen/action"
|
||||
import { RSSHubCategoryCopyMap } from "./copy"
|
||||
import { useSearchPageContext } from "./ctx"
|
||||
import { DiscoverContext } from "./DiscoverContext"
|
||||
import { SearchTabBar } from "./SearchTabBar"
|
||||
|
|
@ -68,6 +68,7 @@ export const DiscoverHeader = () => {
|
|||
return <DiscoverHeaderImpl />
|
||||
}
|
||||
const DiscoverHeaderImpl = () => {
|
||||
const { t } = useTranslation("common")
|
||||
const frame = useSafeAreaFrame()
|
||||
const insets = useSafeAreaInsets()
|
||||
const sheetModal = useScreenIsInSheetModal()
|
||||
|
|
@ -97,7 +98,7 @@ const DiscoverHeaderImpl = () => {
|
|||
|
||||
<TabBar
|
||||
tabs={RSSHubCategories.map((category) => ({
|
||||
name: RSSHubCategoryCopyMap[category],
|
||||
name: t(`discover.category.${category}`),
|
||||
value: category,
|
||||
}))}
|
||||
tabScrollContainerAnimatedX={animatedX}
|
||||
|
|
@ -112,6 +113,7 @@ const DiscoverHeaderImpl = () => {
|
|||
|
||||
const PlaceholerSearchBar = () => {
|
||||
const labelColor = useColor("secondaryLabel")
|
||||
const { t } = useTranslation("common")
|
||||
return (
|
||||
<Pressable
|
||||
style={styles.searchbar}
|
||||
|
|
@ -126,7 +128,7 @@ const PlaceholerSearchBar = () => {
|
|||
>
|
||||
<Search2CuteReIcon color={labelColor} height={18} width={18} />
|
||||
<Text className="text-secondary-label ml-1" style={styles.searchPlaceholderText}>
|
||||
Search
|
||||
{t("words.search")}
|
||||
</Text>
|
||||
</View>
|
||||
</Pressable>
|
||||
|
|
@ -159,6 +161,7 @@ const ComposeSearchBar = () => {
|
|||
}
|
||||
|
||||
const SearchInput = () => {
|
||||
const { t } = useTranslation("common")
|
||||
const { searchFocusedAtom, searchValueAtom } = useSearchPageContext()
|
||||
const [isFocused, setIsFocused] = useAtom(searchFocusedAtom)
|
||||
const placeholderTextColor = useColor("secondaryLabel")
|
||||
|
|
@ -232,7 +235,7 @@ const SearchInput = () => {
|
|||
<Search2CuteReIcon color={placeholderTextColor} height={18} width={18} />
|
||||
{!searchValue && !tempSearchValue && (
|
||||
<Text className="text-secondary-label ml-2" style={styles.searchPlaceholderText}>
|
||||
Search
|
||||
{t("words.search")}
|
||||
</Text>
|
||||
)}
|
||||
</Animated.View>
|
||||
|
|
@ -260,7 +263,7 @@ const SearchInput = () => {
|
|||
<Animated.View style={skeletonAnimatedStyle} pointerEvents="none">
|
||||
<Search2CuteReIcon color={placeholderTextColor} height={18} width={18} />
|
||||
<Text className="text-secondary-label ml-1" style={styles.searchPlaceholderText}>
|
||||
Search
|
||||
{t("words.search")}
|
||||
</Text>
|
||||
</Animated.View>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ export function EntryNormalItem({ entryId, extraData }: { entryId: string; extra
|
|||
<RelativeDateTime
|
||||
date={entry.publishedAt}
|
||||
className="text-secondary-label text-xs font-medium"
|
||||
postfixText="ago"
|
||||
/>
|
||||
</View>
|
||||
{!!entry.title && (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useEffect } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import type { StyleProp, ViewStyle } from "react-native"
|
||||
import { ScrollView, useWindowDimensions, View } from "react-native"
|
||||
import Animated, {
|
||||
|
|
@ -106,6 +107,7 @@ function ViewItem({ view }: { view: ViewDefinition }) {
|
|||
const isActive = selectedFeed?.type === "view" && selectedFeed.viewId === view.view
|
||||
const unreadCount = useUnreadCountByView(view.view)
|
||||
const borderColor = useColor("gray5")
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
return (
|
||||
<TimelineViewSelectorContextMenu type="view" viewId={view.view}>
|
||||
|
|
@ -123,7 +125,7 @@ function ViewItem({ view }: { view: ViewDefinition }) {
|
|||
className="text-sm font-semibold text-white"
|
||||
numberOfLines={1}
|
||||
>
|
||||
{view.name}
|
||||
{t(view.name)}
|
||||
</Animated.Text>
|
||||
{!!unreadCount && (
|
||||
<Animated.View exiting={FadeOut} className="size-1.5 rounded-full bg-white" />
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { jotaiStore } from "@follow/utils"
|
|||
import { EventBus } from "@follow/utils/src/event-bus"
|
||||
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai"
|
||||
import { createContext, useCallback, useContext, useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { views } from "@/src/constants/views"
|
||||
import { usePrefetchEntries } from "@/src/store/entry/hooks"
|
||||
|
|
@ -191,6 +192,7 @@ export const useSelectedFeedTitle = () => {
|
|||
const feed = useFeed(selectedFeed && selectedFeed.type === "feed" ? selectedFeed.feedId : "")
|
||||
const list = useList(selectedFeed && selectedFeed.type === "list" ? selectedFeed.listId : "")
|
||||
const inbox = useInbox(selectedFeed && selectedFeed.type === "inbox" ? selectedFeed.inboxId : "")
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
if (!selectedFeed) {
|
||||
return ""
|
||||
|
|
@ -198,7 +200,7 @@ export const useSelectedFeedTitle = () => {
|
|||
|
||||
switch (selectedFeed.type) {
|
||||
case "view": {
|
||||
return viewDef?.name
|
||||
return viewDef?.name ? t(viewDef.name) : ""
|
||||
}
|
||||
case "feed": {
|
||||
return selectedFeed.feedId === FEED_COLLECTION_LIST ? "Collections" : (feed?.title ?? "")
|
||||
|
|
@ -210,7 +212,7 @@ export const useSelectedFeedTitle = () => {
|
|||
return list?.title
|
||||
}
|
||||
case "inbox": {
|
||||
return inbox?.title ?? "Inbox"
|
||||
return inbox?.title ?? t("words.inbox")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { UserRole } from "@follow/constants"
|
||||
import * as FileSystem from "expo-file-system"
|
||||
import type { ParseKeys } from "i18next"
|
||||
import type { FC } from "react"
|
||||
import { Fragment, useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Alert, PixelRatio, View } from "react-native"
|
||||
|
||||
import {
|
||||
|
|
@ -42,7 +44,7 @@ import { NotificationsScreen } from "./routes/Notifications"
|
|||
import { PrivacyScreen } from "./routes/Privacy"
|
||||
|
||||
interface GroupNavigationLink {
|
||||
label: string
|
||||
label: Extract<ParseKeys<"settings">, `titles.${string}`>
|
||||
icon: React.ElementType
|
||||
onPress: (data: { navigation: Navigation }) => void
|
||||
iconBackgroundColor: string
|
||||
|
|
@ -53,7 +55,7 @@ interface GroupNavigationLink {
|
|||
}
|
||||
const SettingGroupNavigationLinks: GroupNavigationLink[] = [
|
||||
{
|
||||
label: "General",
|
||||
label: "titles.general",
|
||||
icon: Settings1CuteFiIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(GeneralScreen)
|
||||
|
|
@ -61,7 +63,7 @@ const SettingGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
iconBackgroundColor: "#F59E0B",
|
||||
},
|
||||
{
|
||||
label: "Notifications",
|
||||
label: "titles.notifications",
|
||||
icon: BellRingingCuteFiIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(NotificationsScreen)
|
||||
|
|
@ -71,7 +73,7 @@ const SettingGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
anonymous: false,
|
||||
},
|
||||
{
|
||||
label: "Appearance",
|
||||
label: "titles.appearance",
|
||||
icon: PaletteCuteFiIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(AppearanceScreen)
|
||||
|
|
@ -79,7 +81,7 @@ const SettingGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
iconBackgroundColor: "#FCD34D",
|
||||
},
|
||||
{
|
||||
label: "Data",
|
||||
label: "titles.data_control",
|
||||
icon: DatabaseIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(DataScreen)
|
||||
|
|
@ -88,7 +90,7 @@ const SettingGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
anonymous: false,
|
||||
},
|
||||
{
|
||||
label: "Account",
|
||||
label: "titles.account",
|
||||
icon: UserSettingCuteFiIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(AccountScreen)
|
||||
|
|
@ -100,7 +102,7 @@ const SettingGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
|
||||
const BetaGroupNavigationLinks: GroupNavigationLink[] = [
|
||||
{
|
||||
label: "Invitation",
|
||||
label: "titles.invitations",
|
||||
icon: LoveCuteFiIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(InvitationsScreen)
|
||||
|
|
@ -113,7 +115,7 @@ const BetaGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
|
||||
const DataGroupNavigationLinks: GroupNavigationLink[] = [
|
||||
{
|
||||
label: "Actions",
|
||||
label: "titles.actions",
|
||||
icon: Magic2CuteFiIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(ActionsScreen)
|
||||
|
|
@ -124,7 +126,7 @@ const DataGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
},
|
||||
|
||||
{
|
||||
label: "Feeds",
|
||||
label: "titles.feeds",
|
||||
icon: CertificateCuteFiIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(FeedsScreen)
|
||||
|
|
@ -135,7 +137,7 @@ const DataGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
trialNotAllowed: true,
|
||||
},
|
||||
{
|
||||
label: "Lists",
|
||||
label: "titles.lists",
|
||||
icon: RadaCuteFiIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(ListsScreen)
|
||||
|
|
@ -149,7 +151,7 @@ const DataGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
|
||||
const PrivacyGroupNavigationLinks: GroupNavigationLink[] = [
|
||||
{
|
||||
label: "Privacy",
|
||||
label: "titles.privacy",
|
||||
icon: SafeLockFilledIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(PrivacyScreen)
|
||||
|
|
@ -157,7 +159,7 @@ const PrivacyGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
iconBackgroundColor: "#EF4444",
|
||||
},
|
||||
{
|
||||
label: "About",
|
||||
label: "titles.about",
|
||||
icon: StarCuteFiIcon,
|
||||
onPress: ({ navigation }) => {
|
||||
navigation.pushControllerView(AboutScreen)
|
||||
|
|
@ -168,7 +170,7 @@ const PrivacyGroupNavigationLinks: GroupNavigationLink[] = [
|
|||
|
||||
const ActionGroupNavigationLinks: GroupNavigationLink[] = [
|
||||
{
|
||||
label: "Sign out",
|
||||
label: "titles.sign_out",
|
||||
icon: ExitCuteFiIcon,
|
||||
onPress: () => {
|
||||
Alert.alert("Sign out", "Are you sure you want to sign out?", [
|
||||
|
|
@ -196,6 +198,7 @@ const NavigationLinkGroup: FC<{
|
|||
}> = ({ links }) => {
|
||||
const navigation = useNavigation()
|
||||
const role = useRole()
|
||||
const { t } = useTranslation("settings")
|
||||
|
||||
return (
|
||||
<GroupedInsetListCard>
|
||||
|
|
@ -205,7 +208,7 @@ const NavigationLinkGroup: FC<{
|
|||
return (
|
||||
<GroupedInsetListNavigationLink
|
||||
key={link.label}
|
||||
label={link.label}
|
||||
label={t(link.label)}
|
||||
icon={
|
||||
<GroupedInsetListNavigationLinkIcon backgroundColor={link.iconBackgroundColor}>
|
||||
<link.icon height={18} width={18} color="#fff" />
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import {
|
|||
GroupedInsetListSectionHeader,
|
||||
} from "@/src/components/ui/grouped/GroupedList"
|
||||
import { Switch } from "@/src/components/ui/switch/Switch"
|
||||
import { updateDayjsLocale } from "@/src/lib/i18n"
|
||||
import type { NavigationControllerView } from "@/src/lib/navigation/types"
|
||||
|
||||
function LanguageSelect({ settingKey }: { settingKey: "language" | "actionLanguage" }) {
|
||||
|
|
@ -47,6 +48,7 @@ function LanguageSelect({ settingKey }: { settingKey: "language" | "actionLangua
|
|||
setGeneralSetting(settingKey, value)
|
||||
if (settingKey === "language") {
|
||||
i18next.changeLanguage(value)
|
||||
updateDayjsLocale(value)
|
||||
}
|
||||
}}
|
||||
displayValue={t(`langs.${language}` as any)}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import type { FeedViewType } from "@follow/constants"
|
||||
import type { FlashList } from "@shopify/flash-list"
|
||||
import type { ParseKeys } from "i18next"
|
||||
import { useMemo, useState } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Text, View } from "react-native"
|
||||
import { useEventCallback } from "usehooks-ts"
|
||||
|
||||
|
|
@ -65,12 +67,12 @@ export const SubscriptionList = ({
|
|||
|
||||
const data = useMemo(
|
||||
() => [
|
||||
"Starred",
|
||||
"Lists",
|
||||
"words.starred",
|
||||
"words.lists",
|
||||
...sortedListIds,
|
||||
"Inbox",
|
||||
"words.inbox",
|
||||
...inboxes,
|
||||
"Feeds",
|
||||
"words.feeds",
|
||||
...sortedGrouped,
|
||||
...sortedUnGrouped,
|
||||
],
|
||||
|
|
@ -138,26 +140,26 @@ const ItemRender = ({
|
|||
}) => {
|
||||
if (typeof item === "string") {
|
||||
switch (item) {
|
||||
case "Starred": {
|
||||
case "words.starred": {
|
||||
return <StarItem />
|
||||
}
|
||||
case "Inbox": {
|
||||
case "words.inbox": {
|
||||
if (!extraData) return null
|
||||
const { inboxIndexRange } = extraData
|
||||
if (inboxIndexRange[0] > inboxIndexRange[1]) return null
|
||||
return <SectionTitle title={item} />
|
||||
return <SectionTitle transKey={item} />
|
||||
}
|
||||
case "Lists": {
|
||||
case "words.lists": {
|
||||
if (!extraData) return null
|
||||
const { listsIndexRange } = extraData
|
||||
if (listsIndexRange[0] > listsIndexRange[1]) return null
|
||||
return <SectionTitle title={item} />
|
||||
return <SectionTitle transKey={item} />
|
||||
}
|
||||
case "Feeds": {
|
||||
case "words.feeds": {
|
||||
if (!extraData) return null
|
||||
const { feedsIndexRange } = extraData
|
||||
if (feedsIndexRange[0] > feedsIndexRange[1]) return null
|
||||
return <SectionTitle title={item} />
|
||||
return <SectionTitle transKey={item} />
|
||||
}
|
||||
default: {
|
||||
if (!extraData) return null
|
||||
|
|
@ -203,7 +205,8 @@ const ItemRender = ({
|
|||
)
|
||||
}
|
||||
|
||||
const SectionTitle = ({ title }: { title: string }) => {
|
||||
const SectionTitle = ({ transKey }: { transKey: ParseKeys<"common"> }) => {
|
||||
const { t } = useTranslation("common")
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
|
|
@ -214,7 +217,7 @@ const SectionTitle = ({ title }: { title: string }) => {
|
|||
}}
|
||||
>
|
||||
<Text className="text-secondary-label" ellipsizeMode="tail" numberOfLines={1}>
|
||||
{title}
|
||||
{t(transKey)}
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
|
|
@ -222,6 +225,7 @@ const SectionTitle = ({ title }: { title: string }) => {
|
|||
|
||||
const StarItem = () => {
|
||||
const navigation = useNavigation()
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
return (
|
||||
<GroupedInsetListCard showSeparator={false} className="mt-4">
|
||||
|
|
@ -242,7 +246,7 @@ const StarItem = () => {
|
|||
>
|
||||
<StarCuteFiIcon color="rgb(245, 158, 11)" height={20} width={20} />
|
||||
<Text className="text-text ml-2 font-medium" style={{ marginLeft: GROUPED_ICON_TEXT_GAP }}>
|
||||
Starred
|
||||
{t("words.starred")}
|
||||
</Text>
|
||||
</ItemPressable>
|
||||
</GroupedInsetListCard>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { FeedViewType } from "@follow/constants"
|
||||
import { Fragment, useCallback, useEffect, useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import {
|
||||
ActivityIndicator,
|
||||
FlatList,
|
||||
|
|
@ -62,6 +63,7 @@ export const ProfileScreen: NavigationControllerView<{
|
|||
}
|
||||
|
||||
function ProfileScreenImpl(props: { userId: string }) {
|
||||
const { t } = useTranslation()
|
||||
const scrollY = useSharedValue(0)
|
||||
const {
|
||||
data: subscriptions,
|
||||
|
|
@ -107,7 +109,9 @@ function ProfileScreenImpl(props: { userId: string }) {
|
|||
>
|
||||
<BlurEffect />
|
||||
<InternalNavigationHeader
|
||||
title={`${user?.name}'s Profile`}
|
||||
title={t("profile.title", {
|
||||
name: user?.name,
|
||||
})}
|
||||
headerRight={
|
||||
<UINavigationHeaderActionButton onPress={openShareUrl}>
|
||||
<Share3CuteReIcon color={textLabelColor} />
|
||||
|
|
@ -152,6 +156,8 @@ type PickedFeedModel = Pick<
|
|||
view: FeedViewType
|
||||
}
|
||||
const SubscriptionList = ({ subscriptions }: { subscriptions: Subscription[] }) => {
|
||||
const { t: tCommon } = useTranslation("common")
|
||||
const { t } = useTranslation()
|
||||
const { lists, feeds, groupedFeeds } = useMemo(() => {
|
||||
const lists = [] as PickedListModel[]
|
||||
const feeds = [] as PickedFeedModel[]
|
||||
|
|
@ -201,7 +207,7 @@ const SubscriptionList = ({ subscriptions }: { subscriptions: Subscription[] })
|
|||
<View>
|
||||
{lists.length > 0 && (
|
||||
<Fragment>
|
||||
<SectionHeader title="Lists" />
|
||||
<SectionHeader title={tCommon("words.lists")} />
|
||||
|
||||
<GroupedInsetListCard>
|
||||
<FlatList
|
||||
|
|
@ -215,7 +221,7 @@ const SubscriptionList = ({ subscriptions }: { subscriptions: Subscription[] })
|
|||
)}
|
||||
{hasFeeds && (
|
||||
<View className="mt-4">
|
||||
<SectionHeader title="Feeds" />
|
||||
<SectionHeader title={tCommon("words.feeds")} />
|
||||
{Object.entries(groupedFeeds).map(([category, feeds]) => (
|
||||
<Fragment key={category}>
|
||||
<GroupedInsetListSectionHeader label={category} marginSize="small" />
|
||||
|
|
@ -230,7 +236,10 @@ const SubscriptionList = ({ subscriptions }: { subscriptions: Subscription[] })
|
|||
</Fragment>
|
||||
))}
|
||||
|
||||
<GroupedInsetListSectionHeader label="Uncategorized Feeds" marginSize="small" />
|
||||
<GroupedInsetListSectionHeader
|
||||
label={t("profile.uncategorized_feeds")}
|
||||
marginSize="small"
|
||||
/>
|
||||
<GroupedInsetListCard>
|
||||
<FlatList
|
||||
scrollEnabled={false}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useContext } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import type { ScrollView } from "react-native"
|
||||
import { Text, TouchableOpacity, View } from "react-native"
|
||||
import type { SharedValue } from "react-native-reanimated"
|
||||
|
|
@ -73,6 +74,7 @@ const SettingHeader = ({ scrollY }: { scrollY: SharedValue<number> }) => {
|
|||
}
|
||||
|
||||
const EditProfileButton = () => {
|
||||
const { t } = useTranslation("common")
|
||||
const navigation = useNavigation()
|
||||
return (
|
||||
<TouchableOpacity
|
||||
|
|
@ -81,7 +83,7 @@ const EditProfileButton = () => {
|
|||
onPress={() => navigation.pushControllerView(EditProfileScreen)}
|
||||
>
|
||||
<BlurEffect />
|
||||
<Text className="text-label text-sm font-medium">Edit</Text>
|
||||
<Text className="text-label text-sm font-medium">{t("words.edit")}</Text>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,12 +96,6 @@
|
|||
"feed_item.claimed_feed": "خلاصة مطالبة",
|
||||
"feed_item.error_since": "خطأ منذ",
|
||||
"feed_item.not_publicly_visible": "غير مرئية بشكل عام في صفحة ملفك الشخصي",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "ملفات صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"mark_all_read_button.auto_confirm_info": "سيتم التأكيد تلقائيًا بعد {{countdown}} ثوانٍ.",
|
||||
"mark_all_read_button.confirm": "تأكيد",
|
||||
"mark_all_read_button.confirm_mark_all": "هل تريد تحديد <which /> كمقروء؟",
|
||||
|
|
|
|||
|
|
@ -100,12 +100,6 @@
|
|||
"feed_item.claimed_feed": "خلاصة مدعاة",
|
||||
"feed_item.error_since": "خطأ منذ",
|
||||
"feed_item.not_publicly_visible": "غير مرئي علنًا في صفحة ملفك الشخصي",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "صوتيات",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"mark_all_read_button.auto_confirm_info": "سيتم التأكيد تلقائيًا بعد {{countdown}} ثوانٍ.",
|
||||
"mark_all_read_button.confirm": "تأكيد",
|
||||
"mark_all_read_button.confirm_mark_all": "تحديد <which /> كمقروء؟",
|
||||
|
|
|
|||
|
|
@ -100,12 +100,6 @@
|
|||
"feed_item.claimed_feed": "تمت المطالبة بالتغذية",
|
||||
"feed_item.error_since": "خطأ منذ",
|
||||
"feed_item.not_publicly_visible": "غير مرئي للجمهور في صفحة ملفك الشخصي",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "مقاطع صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"mark_all_read_button.auto_confirm_info": "سيتم التأكيد تلقائيًا بعد {{countdown}} ثوانٍ.",
|
||||
"mark_all_read_button.confirm": "تأكيد",
|
||||
"mark_all_read_button.confirm_mark_all": "وضع علامة <which /> كمقروء؟",
|
||||
|
|
|
|||
|
|
@ -96,12 +96,6 @@
|
|||
"feed_item.claimed_feed": "الموجز المُطالب به",
|
||||
"feed_item.error_since": "خطأ منذ",
|
||||
"feed_item.not_publicly_visible": "غير مرئي علنًا في صفحة ملفك الشخصي",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "ملفات صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"mark_all_read_button.auto_confirm_info": "سيتم التأكيد تلقائيًا بعد {{countdown}} ثوانٍ.",
|
||||
"mark_all_read_button.confirm": "تأكيد",
|
||||
"mark_all_read_button.confirm_mark_all": "وضع علامة على <which /> كمقروء؟",
|
||||
|
|
|
|||
|
|
@ -93,12 +93,6 @@
|
|||
"feed_item.claimed_feed": "خلاصة مطالبة",
|
||||
"feed_item.error_since": "خطأ منذ",
|
||||
"feed_item.not_publicly_visible": "غير مرئي بشكل عام في صفحة ملفك الشخصي",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "ملفات صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"mark_all_read_button.auto_confirm_info": "سيتم التأكيد تلقائيًا بعد {{countdown}} ثوانٍ.",
|
||||
"mark_all_read_button.confirm": "تأكيد",
|
||||
"mark_all_read_button.confirm_mark_all": "تمييز <which /> كمقروء؟",
|
||||
|
|
|
|||
|
|
@ -97,12 +97,6 @@
|
|||
"feed_item.claimed_feed": "تغذية مُدعاة",
|
||||
"feed_item.error_since": "خطأ منذ",
|
||||
"feed_item.not_publicly_visible": "غير مرئية علنًا في صفحة ملفك الشخصي",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "مقاطع صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "مقاطع فيديو",
|
||||
"mark_all_read_button.auto_confirm_info": "سيتم التأكيد تلقائيًا بعد {{countdown}} ثوانٍ.",
|
||||
"mark_all_read_button.confirm": "تأكيد",
|
||||
"mark_all_read_button.confirm_mark_all": "وضع علامة <which /> كمقروء؟",
|
||||
|
|
|
|||
|
|
@ -100,12 +100,6 @@
|
|||
"feed_item.claimed_feed": "Beanspruchter Feed",
|
||||
"feed_item.error_since": "Fehler seit",
|
||||
"feed_item.not_publicly_visible": "Nicht öffentlich auf Ihrer Profilseite sichtbar",
|
||||
"feed_view_type.articles": "Artikel",
|
||||
"feed_view_type.audios": "Audios",
|
||||
"feed_view_type.notifications": "Benachrichtigungen",
|
||||
"feed_view_type.pictures": "Bilder",
|
||||
"feed_view_type.social_media": "Soziale Medien",
|
||||
"feed_view_type.videos": "Videos",
|
||||
"mark_all_read_button.auto_confirm_info": "Wird nach {{countdown}} Sekunden automatisch bestätigt.",
|
||||
"mark_all_read_button.confirm": "Bestätigen",
|
||||
"mark_all_read_button.confirm_mark_all": "<which /> als gelesen markieren?",
|
||||
|
|
|
|||
|
|
@ -39,29 +39,6 @@
|
|||
"boost.feed_being_boosted": "Feed being boosted",
|
||||
"boost.remaining_boosts_to_level_up": "{{remainingBoostsToLevelUp}} more boost will unlock the next level of benefits!",
|
||||
"discover.any_url_or_keyword": "Any URL or Keyword",
|
||||
"discover.category.all": "All",
|
||||
"discover.category.anime": "ACG",
|
||||
"discover.category.bbs": "BBS",
|
||||
"discover.category.blog": "Blog",
|
||||
"discover.category.design": "Design",
|
||||
"discover.category.finance": "Finance",
|
||||
"discover.category.forecast": "Forecast",
|
||||
"discover.category.game": "Gaming",
|
||||
"discover.category.government": "Government",
|
||||
"discover.category.journal": "Scientific Journal",
|
||||
"discover.category.live": "Live",
|
||||
"discover.category.multimedia": "Multimedia",
|
||||
"discover.category.new-media": "New Media",
|
||||
"discover.category.picture": "Picture",
|
||||
"discover.category.program-update": "Application Updates",
|
||||
"discover.category.programming": "Programming",
|
||||
"discover.category.reading": "Reading",
|
||||
"discover.category.shopping": "Shopping",
|
||||
"discover.category.social-media": "Social Media",
|
||||
"discover.category.study": "Study",
|
||||
"discover.category.traditional-media": "News",
|
||||
"discover.category.travel": "Travel",
|
||||
"discover.category.university": "University",
|
||||
"discover.default_option": " (default)",
|
||||
"discover.feed_description": "The description of this feed is as follows, and you can fill out the parameter form with the relevant information.",
|
||||
"discover.feed_maintainers": "This feed is provided by RSSHub, with credit to <maintainers />",
|
||||
|
|
@ -228,12 +205,6 @@
|
|||
"feed_item.claimed_list": "Claimed List",
|
||||
"feed_item.error_since": "Error since",
|
||||
"feed_item.not_publicly_visible": "Not publicly visible on your profile page",
|
||||
"feed_view_type.articles": "Articles",
|
||||
"feed_view_type.audios": "Audios",
|
||||
"feed_view_type.notifications": "Notifications",
|
||||
"feed_view_type.pictures": "Pictures",
|
||||
"feed_view_type.social_media": "Social Media",
|
||||
"feed_view_type.videos": "Videos",
|
||||
"login.confirm_password.label": "Confirm Password",
|
||||
"login.continueWith": "Continue with {{provider}}",
|
||||
"login.email": "Email",
|
||||
|
|
|
|||
|
|
@ -64,12 +64,6 @@
|
|||
"feed_form.update_follow": "Actualizar seguimiento",
|
||||
"feed_form.updated": "🎉 Actualizado.",
|
||||
"feed_form.view": "Vista",
|
||||
"feed_view_type.articles": "Artículos",
|
||||
"feed_view_type.audios": "Audios",
|
||||
"feed_view_type.notifications": "Notificaciones",
|
||||
"feed_view_type.pictures": "Imágenes",
|
||||
"feed_view_type.social_media": "Redes Sociales",
|
||||
"feed_view_type.videos": "Videos",
|
||||
"mark_all_read_button.auto_confirm_info": "Confirmación automática después de {{countdown}} segundos.",
|
||||
"mark_all_read_button.confirm": "Confirmar",
|
||||
"mark_all_read_button.confirm_mark_all": "¿Marcar <which /> como leído?",
|
||||
|
|
|
|||
|
|
@ -93,12 +93,6 @@
|
|||
"feed_item.claimed_feed": "Vahvistettu syöte",
|
||||
"feed_item.error_since": "Virhe alkaen",
|
||||
"feed_item.not_publicly_visible": "Ei julkisesti näkyvissä profiilisivullasi",
|
||||
"feed_view_type.articles": "Artikkelit",
|
||||
"feed_view_type.audios": "Äänitteet",
|
||||
"feed_view_type.notifications": "Ilmoitukset",
|
||||
"feed_view_type.pictures": "Kuvat",
|
||||
"feed_view_type.social_media": "Sosiaalinen media",
|
||||
"feed_view_type.videos": "Videot",
|
||||
"mark_all_read_button.auto_confirm_info": "Vahvistetaan automaattisesti {{countdown}} sekunnin kuluttua.",
|
||||
"mark_all_read_button.confirm": "Vahvista",
|
||||
"mark_all_read_button.confirm_mark_all": "Merkitäänkö <which /> luetuksi?",
|
||||
|
|
|
|||
|
|
@ -93,12 +93,6 @@
|
|||
"feed_item.claimed_feed": "Flux Réclamé",
|
||||
"feed_item.error_since": "Erreur depuis",
|
||||
"feed_item.not_publicly_visible": "Non visible publiquement sur votre page de profil",
|
||||
"feed_view_type.articles": "Articles",
|
||||
"feed_view_type.audios": "Audios",
|
||||
"feed_view_type.notifications": "Notifications",
|
||||
"feed_view_type.pictures": "Images",
|
||||
"feed_view_type.social_media": "Réseaux sociaux",
|
||||
"feed_view_type.videos": "Vidéos",
|
||||
"mark_all_read_button.auto_confirm_info": "Sera confirmé automatiquement après {{countdown}}s.",
|
||||
"mark_all_read_button.confirm": "Confirmer",
|
||||
"mark_all_read_button.confirm_mark_all": "Marquer <which /> comme lu ?",
|
||||
|
|
|
|||
|
|
@ -93,12 +93,6 @@
|
|||
"feed_item.claimed_feed": "Feed Reclamato",
|
||||
"feed_item.error_since": "Errore da",
|
||||
"feed_item.not_publicly_visible": "Non visibile pubblicamente sulla tua pagina profilo",
|
||||
"feed_view_type.articles": "Articoli",
|
||||
"feed_view_type.audios": "Audio",
|
||||
"feed_view_type.notifications": "Notifiche",
|
||||
"feed_view_type.pictures": "Immagini",
|
||||
"feed_view_type.social_media": "Social Media",
|
||||
"feed_view_type.videos": "Video",
|
||||
"mark_all_read_button.auto_confirm_info": "Sarà confermato automaticamente dopo {{countdown}}s.",
|
||||
"mark_all_read_button.confirm": "Conferma",
|
||||
"mark_all_read_button.confirm_mark_all": "Segna <which /> come letto?",
|
||||
|
|
|
|||
|
|
@ -39,29 +39,6 @@
|
|||
"boost.feed_being_boosted": "フィードをブーストしています",
|
||||
"boost.remaining_boosts_to_level_up": "{{remainingBoostsToLevelUp}} さらなるレベルのブースト アンロックは特典として提供されます!",
|
||||
"discover.any_url_or_keyword": "任意の URL またはキーワード",
|
||||
"discover.category.all": "すべて",
|
||||
"discover.category.anime": "ACG",
|
||||
"discover.category.bbs": "BBS",
|
||||
"discover.category.blog": "ブログ",
|
||||
"discover.category.design": "デザイン",
|
||||
"discover.category.finance": "金融",
|
||||
"discover.category.forecast": "予報",
|
||||
"discover.category.game": "ゲーム",
|
||||
"discover.category.government": "政府",
|
||||
"discover.category.journal": "科学/学術",
|
||||
"discover.category.live": "Live",
|
||||
"discover.category.multimedia": "マルチメディア",
|
||||
"discover.category.new-media": "新メディア",
|
||||
"discover.category.picture": "ピクチャー",
|
||||
"discover.category.program-update": "アプリ",
|
||||
"discover.category.programming": "プログラミング",
|
||||
"discover.category.reading": "読みもの",
|
||||
"discover.category.shopping": "買い物",
|
||||
"discover.category.social-media": "ソーシャルメディア",
|
||||
"discover.category.study": "学習",
|
||||
"discover.category.traditional-media": "ニュース",
|
||||
"discover.category.travel": "旅行",
|
||||
"discover.category.university": "大学",
|
||||
"discover.default_option": " (デフォルト)",
|
||||
"discover.feed_description": "このフィードの説明は Folo で表示されます、またパラメータ フォームに関連する情報を記入することができます。",
|
||||
"discover.feed_maintainers": "フィードは RSSHub が提供し <maintainers /> とともにクレジットされます。",
|
||||
|
|
@ -226,12 +203,6 @@
|
|||
"feed_item.claimed_list": "クレームされたリスト",
|
||||
"feed_item.error_since": "エラー発生時刻",
|
||||
"feed_item.not_publicly_visible": "プロフィールページに公開されていません",
|
||||
"feed_view_type.articles": "記事",
|
||||
"feed_view_type.audios": "オーディオ",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "画像",
|
||||
"feed_view_type.social_media": "ソーシャルメディア",
|
||||
"feed_view_type.videos": "動画",
|
||||
"login.confirm_password.label": "パスワードの確認",
|
||||
"login.continueWith": "{{provider}} で続ける",
|
||||
"login.email": "Email",
|
||||
|
|
|
|||
|
|
@ -39,29 +39,6 @@
|
|||
"boost.feed_being_boosted": "피드가 부스트 중",
|
||||
"boost.remaining_boosts_to_level_up": "{{remainingBoostsToLevelUp}} 더 많은 부스트를 하면 다음 단계의 혜택이 잠금 해제됩니다!",
|
||||
"discover.any_url_or_keyword": "임의의 URL 또는 키워드",
|
||||
"discover.category.all": "전체",
|
||||
"discover.category.anime": "ACG",
|
||||
"discover.category.bbs": "BBS",
|
||||
"discover.category.blog": "블로그",
|
||||
"discover.category.design": "디자인",
|
||||
"discover.category.finance": "금융",
|
||||
"discover.category.forecast": "예측",
|
||||
"discover.category.game": "게임",
|
||||
"discover.category.government": "정부",
|
||||
"discover.category.journal": "과학 저널",
|
||||
"discover.category.live": "라이브",
|
||||
"discover.category.multimedia": "멀티미디어",
|
||||
"discover.category.new-media": "뉴미디어",
|
||||
"discover.category.picture": "사진",
|
||||
"discover.category.program-update": "애플리케이션 업데이트",
|
||||
"discover.category.programming": "프로그래밍",
|
||||
"discover.category.reading": "독서",
|
||||
"discover.category.shopping": "쇼핑",
|
||||
"discover.category.social-media": "소셜 미디어",
|
||||
"discover.category.study": "학습",
|
||||
"discover.category.traditional-media": "뉴스",
|
||||
"discover.category.travel": "여행",
|
||||
"discover.category.university": "대학교",
|
||||
"discover.default_option": " (기본값)",
|
||||
"discover.feed_description": "이 피드의 설명은 다음과 같으며, 관련 정보를 사용하여 매개변수 양식을 작성할 수 있습니다.",
|
||||
"discover.feed_maintainers": "이 피드는 RSSHub에서 제공하며, <maintainers />에게 크레딧을 제공합니다.",
|
||||
|
|
@ -226,12 +203,6 @@
|
|||
"feed_item.claimed_list": "클레임된 목록",
|
||||
"feed_item.error_since": "오류 발생:",
|
||||
"feed_item.not_publicly_visible": "프로필 페이지에 공개적으로 표시되지 않음",
|
||||
"feed_view_type.articles": "기사",
|
||||
"feed_view_type.audios": "오디오",
|
||||
"feed_view_type.notifications": "알림",
|
||||
"feed_view_type.pictures": "사진",
|
||||
"feed_view_type.social_media": "소셜 미디어",
|
||||
"feed_view_type.videos": "비디오",
|
||||
"login.confirm_password.label": "비밀번호 확인",
|
||||
"login.continueWith": "{{provider}}로 계속하기",
|
||||
"login.email": "이메일",
|
||||
|
|
|
|||
|
|
@ -93,12 +93,6 @@
|
|||
"feed_item.claimed_feed": "クレームされたフィード",
|
||||
"feed_item.error_since": "エラー発生時刻",
|
||||
"feed_item.not_publicly_visible": "プロフィールページに公開されていません",
|
||||
"feed_view_type.articles": "記事",
|
||||
"feed_view_type.audios": "オーディオ",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "画像",
|
||||
"feed_view_type.social_media": "ソーシャルメディア",
|
||||
"feed_view_type.videos": "動画",
|
||||
"mark_all_read_button.auto_confirm_info": "{{countdown}} 秒後に自動的に確認されます。",
|
||||
"mark_all_read_button.confirm": "確認",
|
||||
"mark_all_read_button.confirm_mark_all": "<which />を既読にしますか?",
|
||||
|
|
|
|||
|
|
@ -39,29 +39,6 @@
|
|||
"boost.feed_being_boosted": "Канал в процессе усиления",
|
||||
"boost.remaining_boosts_to_level_up": "{{remainingBoostsToLevelUp}} усилений для разблокировки следующего уровня преимуществ!",
|
||||
"discover.any_url_or_keyword": "Любой URL или ключевое слово",
|
||||
"discover.category.all": "Все",
|
||||
"discover.category.anime": "Аниме",
|
||||
"discover.category.bbs": "BBS",
|
||||
"discover.category.blog": "Блог",
|
||||
"discover.category.design": "Дизайн",
|
||||
"discover.category.finance": "Финансы",
|
||||
"discover.category.forecast": "Прогнозы",
|
||||
"discover.category.game": "Игры",
|
||||
"discover.category.government": "Государственные",
|
||||
"discover.category.journal": "Научный журнал",
|
||||
"discover.category.live": "Прямой эфир",
|
||||
"discover.category.multimedia": "Мультимедиа",
|
||||
"discover.category.new-media": "Новые медиа",
|
||||
"discover.category.picture": "Изображения",
|
||||
"discover.category.program-update": "Обновления программы",
|
||||
"discover.category.programming": "Программирование",
|
||||
"discover.category.reading": "Чтение",
|
||||
"discover.category.shopping": "Шоппинг",
|
||||
"discover.category.social-media": "Социальные сети",
|
||||
"discover.category.study": "Учёба",
|
||||
"discover.category.traditional-media": "Новости",
|
||||
"discover.category.travel": "Путешествия",
|
||||
"discover.category.university": "Университет",
|
||||
"discover.default_option": " (по умолчанию)",
|
||||
"discover.feed_description": "Описание этого канала следующее, и вы можете заполнить форму параметров с соответствующей информацией.",
|
||||
"discover.feed_maintainers": "Этот канал предоставлен RSSHub, с благодарностью <maintainers />",
|
||||
|
|
@ -222,12 +199,6 @@
|
|||
"feed_item.claimed_list": "Заявленный список",
|
||||
"feed_item.error_since": "Ошибка с",
|
||||
"feed_item.not_publicly_visible": "Не виден на вашей публичной странице профиля",
|
||||
"feed_view_type.articles": "Статьи",
|
||||
"feed_view_type.audios": "Аудио",
|
||||
"feed_view_type.notifications": "Уведомления",
|
||||
"feed_view_type.pictures": "Картинки",
|
||||
"feed_view_type.social_media": "Социальные сети",
|
||||
"feed_view_type.videos": "Видео",
|
||||
"login.confirm_password.label": "Подтвердите пароль",
|
||||
"login.continueWith": "Продолжить с {{provider}}",
|
||||
"login.email": "Электронная почта",
|
||||
|
|
|
|||
|
|
@ -114,12 +114,6 @@
|
|||
"feed_item.claimed_feed": "Talep Edilen Besleme",
|
||||
"feed_item.error_since": "Hata başlangıcı",
|
||||
"feed_item.not_publicly_visible": "Profil sayfanızda herkese açık olarak görünmüyor",
|
||||
"feed_view_type.articles": "Makaleler",
|
||||
"feed_view_type.audios": "Sesler",
|
||||
"feed_view_type.notifications": "Bildirimler",
|
||||
"feed_view_type.pictures": "Resimler",
|
||||
"feed_view_type.social_media": "Sosyal Medya",
|
||||
"feed_view_type.videos": "Videolar",
|
||||
"mark_all_read_button.auto_confirm_info": "{{countdown}} saniye sonra otomatik olarak onaylanacak.",
|
||||
"mark_all_read_button.confirm": "Onayla",
|
||||
"mark_all_read_button.confirm_mark_all": "<which /> okundu olarak işaretlensin mi?",
|
||||
|
|
|
|||
|
|
@ -39,29 +39,6 @@
|
|||
"boost.feed_being_boosted": "已助力",
|
||||
"boost.remaining_boosts_to_level_up": "再助力 {{remainingBoostsToLevelUp}} 次即可解锁下一级福利!",
|
||||
"discover.any_url_or_keyword": "任意链接或关键词",
|
||||
"discover.category.all": "全部",
|
||||
"discover.category.anime": "二次元",
|
||||
"discover.category.bbs": "论坛",
|
||||
"discover.category.blog": "博客",
|
||||
"discover.category.design": "设计",
|
||||
"discover.category.finance": "金融",
|
||||
"discover.category.forecast": "预报预警",
|
||||
"discover.category.game": "游戏",
|
||||
"discover.category.government": "政务消息",
|
||||
"discover.category.journal": "科学期刊",
|
||||
"discover.category.live": "直播",
|
||||
"discover.category.multimedia": "音视频",
|
||||
"discover.category.new-media": "新媒体",
|
||||
"discover.category.picture": "图片",
|
||||
"discover.category.program-update": "程序更新",
|
||||
"discover.category.programming": "编程",
|
||||
"discover.category.reading": "阅读",
|
||||
"discover.category.shopping": "购物",
|
||||
"discover.category.social-media": "社交媒体",
|
||||
"discover.category.study": "学习",
|
||||
"discover.category.traditional-media": "传统媒体",
|
||||
"discover.category.travel": "出行旅游",
|
||||
"discover.category.university": "大学通知",
|
||||
"discover.default_option": "(默认)",
|
||||
"discover.feed_description": "根据描述完善目标订阅源的相关信息。",
|
||||
"discover.feed_maintainers": "由 RSSHub 提供,感谢贡献者 <maintainers />",
|
||||
|
|
@ -228,12 +205,6 @@
|
|||
"feed_item.claimed_list": "已认证列表",
|
||||
"feed_item.error_since": "源失效:",
|
||||
"feed_item.not_publicly_visible": "在个人页面上隐藏",
|
||||
"feed_view_type.articles": "文章",
|
||||
"feed_view_type.audios": "音频",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "图片",
|
||||
"feed_view_type.social_media": "社交媒体",
|
||||
"feed_view_type.videos": "视频",
|
||||
"login.confirm_password.label": "确认密码",
|
||||
"login.continueWith": "使用 {{provider}} 登入",
|
||||
"login.email": "邮件地址",
|
||||
|
|
|
|||
|
|
@ -39,29 +39,6 @@
|
|||
"boost.feed_being_boosted": "動態正在加成中",
|
||||
"boost.remaining_boosts_to_level_up": "還差 {{remainingBoostsToLevelUp}} 次加成即可解鎖下一級優惠!",
|
||||
"discover.any_url_or_keyword": "任何網址或關鍵字",
|
||||
"discover.category.all": "全部",
|
||||
"discover.category.anime": "ACG",
|
||||
"discover.category.bbs": "討論區",
|
||||
"discover.category.blog": "博客",
|
||||
"discover.category.design": "設計",
|
||||
"discover.category.finance": "財經",
|
||||
"discover.category.forecast": "預測",
|
||||
"discover.category.game": "遊戲",
|
||||
"discover.category.government": "政府",
|
||||
"discover.category.journal": "科學期刊",
|
||||
"discover.category.live": "直播",
|
||||
"discover.category.multimedia": "多媒體",
|
||||
"discover.category.new-media": "新媒體",
|
||||
"discover.category.picture": "圖片",
|
||||
"discover.category.program-update": "應用程式更新",
|
||||
"discover.category.programming": "程式設計",
|
||||
"discover.category.reading": "閱讀",
|
||||
"discover.category.shopping": "購物",
|
||||
"discover.category.social-media": "社交媒體",
|
||||
"discover.category.study": "學習",
|
||||
"discover.category.traditional-media": "新聞",
|
||||
"discover.category.travel": "旅遊",
|
||||
"discover.category.university": "大學",
|
||||
"discover.default_option": " (預設)",
|
||||
"discover.feed_description": "此訂閱源的描述如下,你可以根據相關資訊填寫參數表格。",
|
||||
"discover.feed_maintainers": "此訂閱源由 RSSHub 提供,感謝 <maintainers />",
|
||||
|
|
@ -228,12 +205,6 @@
|
|||
"feed_item.claimed_list": "已認領清單",
|
||||
"feed_item.error_since": "錯誤始於",
|
||||
"feed_item.not_publicly_visible": "在你的個人頁面上不公開可見",
|
||||
"feed_view_type.articles": "文章",
|
||||
"feed_view_type.audios": "音訊",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "圖片",
|
||||
"feed_view_type.social_media": "社交媒體",
|
||||
"feed_view_type.videos": "影片",
|
||||
"login.confirm_password.label": "確認密碼",
|
||||
"login.continueWith": "繼續使用 {{provider}}",
|
||||
"login.email": "電子郵件",
|
||||
|
|
|
|||
|
|
@ -39,29 +39,6 @@
|
|||
"boost.feed_being_boosted": "訂閱正在加成",
|
||||
"boost.remaining_boosts_to_level_up": "再次加成 {{remainingBoostsToLevelUp}} 次即可解鎖下一級獎勵!",
|
||||
"discover.any_url_or_keyword": "任何 URL 或關鍵字",
|
||||
"discover.category.all": "全部",
|
||||
"discover.category.anime": "動漫",
|
||||
"discover.category.bbs": "論壇",
|
||||
"discover.category.blog": "部落格",
|
||||
"discover.category.design": "設計",
|
||||
"discover.category.finance": "金融",
|
||||
"discover.category.forecast": "預報預警",
|
||||
"discover.category.game": "遊戲",
|
||||
"discover.category.government": "政府資訊",
|
||||
"discover.category.journal": "科學期刊",
|
||||
"discover.category.live": "直播",
|
||||
"discover.category.multimedia": "多媒體",
|
||||
"discover.category.new-media": "新媒體",
|
||||
"discover.category.picture": "圖片",
|
||||
"discover.category.program-update": "程式更新",
|
||||
"discover.category.programming": "程式設計",
|
||||
"discover.category.reading": "閱讀",
|
||||
"discover.category.shopping": "購物",
|
||||
"discover.category.social-media": "社交媒體",
|
||||
"discover.category.study": "學習",
|
||||
"discover.category.traditional-media": "傳統媒體",
|
||||
"discover.category.travel": "出行旅遊",
|
||||
"discover.category.university": "大學資訊",
|
||||
"discover.default_option": "(預設)",
|
||||
"discover.feed_description": "根據描述完成目標 RSS 摘要的相關資訊。",
|
||||
"discover.feed_maintainers": "由 RSSHub 提供,感謝 <maintainers /> 的支持",
|
||||
|
|
@ -223,12 +200,6 @@
|
|||
"feed_item.claimed_list": "已認領列表",
|
||||
"feed_item.error_since": "RSS 摘要失效:",
|
||||
"feed_item.not_publicly_visible": "在您的個人頁面上隱藏",
|
||||
"feed_view_type.articles": "文章",
|
||||
"feed_view_type.audios": "音訊",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "圖片",
|
||||
"feed_view_type.social_media": "社交媒體",
|
||||
"feed_view_type.videos": "影片",
|
||||
"login.confirm_password.label": "確認密碼",
|
||||
"login.continueWith": "透過 {{provider}} 登入",
|
||||
"login.email": "電子信箱",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
"cancel": "إلغاء",
|
||||
"close": "إغلاق",
|
||||
"confirm": "تأكيد",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "ملفات صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"ok": "موافق",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -25,5 +31,7 @@
|
|||
"words.result": "نتيجة",
|
||||
"words.result_one": "نتيجة",
|
||||
"words.result_other": "نتائج",
|
||||
"words.search": "بحث",
|
||||
"words.starred": "مميزة بنجمة",
|
||||
"words.which.all": "الكل"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
"app.copied_to_clipboard": "تم النسخ إلى الحافظة",
|
||||
"cancel": "إلغاء",
|
||||
"confirm": "تأكيد",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "صوتيات",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"ok": "موافق",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -24,5 +30,7 @@
|
|||
"words.result": "نتيجة",
|
||||
"words.result_one": "نتيجة",
|
||||
"words.result_other": "نتائج",
|
||||
"words.search": "بحث",
|
||||
"words.starred": "المفضلة",
|
||||
"words.which.all": "الكل"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
"app.copied_to_clipboard": "تم النسخ إلى الحافظة",
|
||||
"cancel": "إلغاء",
|
||||
"confirm": "تأكيد",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "مقاطع صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"ok": "موافق",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -24,5 +30,7 @@
|
|||
"words.result": "نتيجة",
|
||||
"words.result_one": "نتيجة",
|
||||
"words.result_other": "نتائج",
|
||||
"words.search": "بحث",
|
||||
"words.starred": "مفضلة",
|
||||
"words.which.all": "الكل"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
"cancel": "إلغاء",
|
||||
"close": "إغلاق",
|
||||
"confirm": "تأكيد",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "ملفات صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"ok": "موافق",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -25,5 +31,7 @@
|
|||
"words.result": "نتيجة",
|
||||
"words.result_one": "نتيجة",
|
||||
"words.result_other": "نتائج",
|
||||
"words.search": "بحث",
|
||||
"words.starred": "المفضلة",
|
||||
"words.which.all": "الكل"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
"cancel": "إلغاء",
|
||||
"close": "إغلاق",
|
||||
"confirm": "تأكيد",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "ملفات صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "فيديوهات",
|
||||
"ok": "حسنًا",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -25,5 +31,7 @@
|
|||
"words.result": "نتيجة",
|
||||
"words.result_one": "نتيجة",
|
||||
"words.result_other": "نتائج",
|
||||
"words.search": "بحث",
|
||||
"words.starred": "مميز",
|
||||
"words.which.all": "الكل"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
"app.copied_to_clipboard": "تم النسخ إلى الحافظة",
|
||||
"cancel": "إلغاء",
|
||||
"confirm": "تأكيد",
|
||||
"feed_view_type.articles": "مقالات",
|
||||
"feed_view_type.audios": "مقاطع صوتية",
|
||||
"feed_view_type.notifications": "إشعارات",
|
||||
"feed_view_type.pictures": "صور",
|
||||
"feed_view_type.social_media": "وسائل التواصل الاجتماعي",
|
||||
"feed_view_type.videos": "مقاطع فيديو",
|
||||
"ok": "موافق",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -24,5 +30,7 @@
|
|||
"words.result": "نتيجة",
|
||||
"words.result_one": "نتيجة",
|
||||
"words.result_other": "نتائج",
|
||||
"words.search": "بحث",
|
||||
"words.starred": "المفضلة",
|
||||
"words.which.all": "الكل"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
"cancel": "Abbrechen",
|
||||
"close": "Schließen",
|
||||
"confirm": "Bestätigen",
|
||||
"feed_view_type.articles": "Artikel",
|
||||
"feed_view_type.audios": "Audios",
|
||||
"feed_view_type.notifications": "Benachrichtigungen",
|
||||
"feed_view_type.pictures": "Bilder",
|
||||
"feed_view_type.social_media": "Soziale Medien",
|
||||
"feed_view_type.videos": "Videos",
|
||||
"ok": "OK",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -25,5 +31,7 @@
|
|||
"words.result": "Ergebnis",
|
||||
"words.result_one": "Ergebnis",
|
||||
"words.result_other": "Ergebnisse",
|
||||
"words.search": "Suche",
|
||||
"words.starred": "Favorisiert",
|
||||
"words.which.all": "Alle"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,35 @@
|
|||
"cancel": "Cancel",
|
||||
"close": "Close",
|
||||
"confirm": "Confirm",
|
||||
"discover.category.all": "All",
|
||||
"discover.category.anime": "ACG",
|
||||
"discover.category.bbs": "BBS",
|
||||
"discover.category.blog": "Blog",
|
||||
"discover.category.design": "Design",
|
||||
"discover.category.finance": "Finance",
|
||||
"discover.category.forecast": "Forecast",
|
||||
"discover.category.game": "Gaming",
|
||||
"discover.category.government": "Government",
|
||||
"discover.category.journal": "Scientific Journal",
|
||||
"discover.category.live": "Live",
|
||||
"discover.category.multimedia": "Multimedia",
|
||||
"discover.category.new-media": "New Media",
|
||||
"discover.category.picture": "Picture",
|
||||
"discover.category.program-update": "Application Updates",
|
||||
"discover.category.programming": "Programming",
|
||||
"discover.category.reading": "Reading",
|
||||
"discover.category.shopping": "Shopping",
|
||||
"discover.category.social-media": "Social Media",
|
||||
"discover.category.study": "Study",
|
||||
"discover.category.traditional-media": "News",
|
||||
"discover.category.travel": "Travel",
|
||||
"discover.category.university": "University",
|
||||
"feed_view_type.articles": "Articles",
|
||||
"feed_view_type.audios": "Audios",
|
||||
"feed_view_type.notifications": "Notifications",
|
||||
"feed_view_type.pictures": "Pictures",
|
||||
"feed_view_type.social_media": "Social Media",
|
||||
"feed_view_type.videos": "Videos",
|
||||
"ok": "OK",
|
||||
"quantifier.piece": "",
|
||||
"retry": "Retry",
|
||||
|
|
@ -24,10 +53,13 @@
|
|||
"words.edit": "Edit",
|
||||
"words.entry": "Entry",
|
||||
"words.expand": "Expand",
|
||||
"words.feeds": "Feeds",
|
||||
"words.follow": "Follow",
|
||||
"words.id": "ID",
|
||||
"words.inbox": "Inbox",
|
||||
"words.items_one": "Item",
|
||||
"words.items_other": "Items",
|
||||
"words.lists": "Lists",
|
||||
"words.local": "local",
|
||||
"words.manage": "Manage",
|
||||
"words.record": "record",
|
||||
|
|
@ -39,6 +71,8 @@
|
|||
"words.result_other": "results",
|
||||
"words.rsshub": "RSSHub",
|
||||
"words.save": "Save",
|
||||
"words.search": "Search",
|
||||
"words.starred": "Starred",
|
||||
"words.submit": "Submit",
|
||||
"words.update": "Update",
|
||||
"words.which.all": "All"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
"cancel": "Cancelar",
|
||||
"close": "Cerrar",
|
||||
"confirm": "Confirmar",
|
||||
"feed_view_type.articles": "Artículos",
|
||||
"feed_view_type.audios": "Audios",
|
||||
"feed_view_type.notifications": "Notificaciones",
|
||||
"feed_view_type.pictures": "Imágenes",
|
||||
"feed_view_type.social_media": "Redes Sociales",
|
||||
"feed_view_type.videos": "Videos",
|
||||
"ok": "OK",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -25,5 +31,7 @@
|
|||
"words.result": "resultado",
|
||||
"words.result_one": "resultado",
|
||||
"words.result_other": "resultados",
|
||||
"words.search": "Buscar",
|
||||
"words.starred": "Favoritos",
|
||||
"words.which.all": "Todo"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
"app.copied_to_clipboard": "Kopioitu leikepöydälle",
|
||||
"cancel": "Peruuta",
|
||||
"confirm": "Vahvista",
|
||||
"feed_view_type.articles": "Artikkelit",
|
||||
"feed_view_type.audios": "Äänitteet",
|
||||
"feed_view_type.notifications": "Ilmoitukset",
|
||||
"feed_view_type.pictures": "Kuvat",
|
||||
"feed_view_type.social_media": "Sosiaalinen media",
|
||||
"feed_view_type.videos": "Videot",
|
||||
"ok": "OK",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -24,5 +30,7 @@
|
|||
"words.result": "tulos",
|
||||
"words.result_one": "tulos",
|
||||
"words.result_other": "tulokset",
|
||||
"words.search": "Hae",
|
||||
"words.starred": "Tähdät",
|
||||
"words.which.all": "Kaikki"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
"cancel": "Annuler",
|
||||
"close": "Fermer",
|
||||
"confirm": "Confirmer",
|
||||
"feed_view_type.articles": "Articles",
|
||||
"feed_view_type.audios": "Audios",
|
||||
"feed_view_type.notifications": "Notifications",
|
||||
"feed_view_type.pictures": "Images",
|
||||
"feed_view_type.social_media": "Réseaux sociaux",
|
||||
"feed_view_type.videos": "Vidéos",
|
||||
"ok": "OK",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -25,5 +31,7 @@
|
|||
"words.result": "résultat",
|
||||
"words.result_one": "résultat",
|
||||
"words.result_other": "résultats",
|
||||
"words.search": "Rechercher",
|
||||
"words.starred": "Favoris",
|
||||
"words.which.all": "Tous"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
"app.copied_to_clipboard": "Copiato negli appunti",
|
||||
"cancel": "Annulla",
|
||||
"confirm": "Conferma",
|
||||
"feed_view_type.articles": "Articoli",
|
||||
"feed_view_type.audios": "Audio",
|
||||
"feed_view_type.notifications": "Notifiche",
|
||||
"feed_view_type.pictures": "Immagini",
|
||||
"feed_view_type.social_media": "Social Media",
|
||||
"feed_view_type.videos": "Video",
|
||||
"ok": "OK",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -24,5 +30,7 @@
|
|||
"words.result": "risultato",
|
||||
"words.result_one": "risultato",
|
||||
"words.result_other": "risultati",
|
||||
"words.search": "Cerca",
|
||||
"words.starred": "Preferiti",
|
||||
"words.which.all": "Tutti"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,35 @@
|
|||
"cancel": "キャンセル",
|
||||
"close": "閉じる",
|
||||
"confirm": "確認",
|
||||
"discover.category.all": "すべて",
|
||||
"discover.category.anime": "ACG",
|
||||
"discover.category.bbs": "BBS",
|
||||
"discover.category.blog": "ブログ",
|
||||
"discover.category.design": "デザイン",
|
||||
"discover.category.finance": "金融",
|
||||
"discover.category.forecast": "予報",
|
||||
"discover.category.game": "ゲーム",
|
||||
"discover.category.government": "政府",
|
||||
"discover.category.journal": "科学/学術",
|
||||
"discover.category.live": "Live",
|
||||
"discover.category.multimedia": "マルチメディア",
|
||||
"discover.category.new-media": "新メディア",
|
||||
"discover.category.picture": "ピクチャー",
|
||||
"discover.category.program-update": "アプリ",
|
||||
"discover.category.programming": "プログラミング",
|
||||
"discover.category.reading": "読みもの",
|
||||
"discover.category.shopping": "買い物",
|
||||
"discover.category.social-media": "ソーシャルメディア",
|
||||
"discover.category.study": "学習",
|
||||
"discover.category.traditional-media": "ニュース",
|
||||
"discover.category.travel": "旅行",
|
||||
"discover.category.university": "大学",
|
||||
"feed_view_type.articles": "記事",
|
||||
"feed_view_type.audios": "オーディオ",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "画像",
|
||||
"feed_view_type.social_media": "ソーシャルメディア",
|
||||
"feed_view_type.videos": "動画",
|
||||
"ok": "OK",
|
||||
"quantifier.piece": "個",
|
||||
"retry": "再試行",
|
||||
|
|
@ -23,10 +52,13 @@
|
|||
"words.edit": "編集",
|
||||
"words.entry": "エントリー",
|
||||
"words.expand": "展開",
|
||||
"words.feeds": "フィード",
|
||||
"words.follow": "フォロー",
|
||||
"words.id": "ID",
|
||||
"words.inbox": "受信トレイ",
|
||||
"words.items_one": "アイテム",
|
||||
"words.items_other": "アイテム",
|
||||
"words.lists": "リスト",
|
||||
"words.local": "ローカル",
|
||||
"words.manage": "マネージ",
|
||||
"words.record": "記録",
|
||||
|
|
@ -38,6 +70,8 @@
|
|||
"words.result_other": "結果",
|
||||
"words.rsshub": "RSSHub",
|
||||
"words.save": "保存",
|
||||
"words.search": "検索",
|
||||
"words.starred": "スター付き",
|
||||
"words.submit": "送信",
|
||||
"words.update": "更新",
|
||||
"words.which.all": "すべて"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,35 @@
|
|||
"cancel": "취소",
|
||||
"close": "닫기",
|
||||
"confirm": "확인",
|
||||
"discover.category.all": "전체",
|
||||
"discover.category.anime": "ACG",
|
||||
"discover.category.bbs": "BBS",
|
||||
"discover.category.blog": "블로그",
|
||||
"discover.category.design": "디자인",
|
||||
"discover.category.finance": "금융",
|
||||
"discover.category.forecast": "예측",
|
||||
"discover.category.game": "게임",
|
||||
"discover.category.government": "정부",
|
||||
"discover.category.journal": "과학 저널",
|
||||
"discover.category.live": "라이브",
|
||||
"discover.category.multimedia": "멀티미디어",
|
||||
"discover.category.new-media": "뉴미디어",
|
||||
"discover.category.picture": "사진",
|
||||
"discover.category.program-update": "애플리케이션 업데이트",
|
||||
"discover.category.programming": "프로그래밍",
|
||||
"discover.category.reading": "독서",
|
||||
"discover.category.shopping": "쇼핑",
|
||||
"discover.category.social-media": "소셜 미디어",
|
||||
"discover.category.study": "학습",
|
||||
"discover.category.traditional-media": "뉴스",
|
||||
"discover.category.travel": "여행",
|
||||
"discover.category.university": "대학교",
|
||||
"feed_view_type.articles": "기사",
|
||||
"feed_view_type.audios": "오디오",
|
||||
"feed_view_type.notifications": "알림",
|
||||
"feed_view_type.pictures": "사진",
|
||||
"feed_view_type.social_media": "소셜 미디어",
|
||||
"feed_view_type.videos": "비디오",
|
||||
"ok": "확인",
|
||||
"quantifier.piece": "",
|
||||
"retry": "재시도",
|
||||
|
|
@ -23,10 +52,13 @@
|
|||
"words.edit": "편집",
|
||||
"words.entry": "항목",
|
||||
"words.expand": "펼치기",
|
||||
"words.feeds": "피드",
|
||||
"words.follow": "팔로우",
|
||||
"words.id": "ID",
|
||||
"words.inbox": "받은편지함",
|
||||
"words.items_one": "항목",
|
||||
"words.items_other": "항목들",
|
||||
"words.lists": "목록",
|
||||
"words.local": "로컬",
|
||||
"words.manage": "관리",
|
||||
"words.record": "기록",
|
||||
|
|
@ -38,6 +70,8 @@
|
|||
"words.result_other": "결과들",
|
||||
"words.rsshub": "RSSHub",
|
||||
"words.save": "저장",
|
||||
"words.search": "검색",
|
||||
"words.starred": "별표 표시됨",
|
||||
"words.submit": "제출",
|
||||
"words.update": "업데이트",
|
||||
"words.which.all": "모두"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
"cancel": "Cancelar",
|
||||
"close": "Fechar",
|
||||
"confirm": "Confirmar",
|
||||
"feed_view_type.articles": "記事",
|
||||
"feed_view_type.audios": "オーディオ",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "画像",
|
||||
"feed_view_type.social_media": "ソーシャルメディア",
|
||||
"feed_view_type.videos": "動画",
|
||||
"ok": "OK",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -25,5 +31,7 @@
|
|||
"words.result": "resultado",
|
||||
"words.result_one": "resultado",
|
||||
"words.result_other": "resultados",
|
||||
"words.search": "検索",
|
||||
"words.starred": "スター付き",
|
||||
"words.which.all": "Todos"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,35 @@
|
|||
"cancel": "Отменить",
|
||||
"close": "Закрыть",
|
||||
"confirm": "Подтвердить",
|
||||
"discover.category.all": "Все",
|
||||
"discover.category.anime": "Аниме",
|
||||
"discover.category.bbs": "BBS",
|
||||
"discover.category.blog": "Блог",
|
||||
"discover.category.design": "Дизайн",
|
||||
"discover.category.finance": "Финансы",
|
||||
"discover.category.forecast": "Прогнозы",
|
||||
"discover.category.game": "Игры",
|
||||
"discover.category.government": "Государственные",
|
||||
"discover.category.journal": "Научный журнал",
|
||||
"discover.category.live": "Прямой эфир",
|
||||
"discover.category.multimedia": "Мультимедиа",
|
||||
"discover.category.new-media": "Новые медиа",
|
||||
"discover.category.picture": "Изображения",
|
||||
"discover.category.program-update": "Обновления программы",
|
||||
"discover.category.programming": "Программирование",
|
||||
"discover.category.reading": "Чтение",
|
||||
"discover.category.shopping": "Шоппинг",
|
||||
"discover.category.social-media": "Социальные сети",
|
||||
"discover.category.study": "Учёба",
|
||||
"discover.category.traditional-media": "Новости",
|
||||
"discover.category.travel": "Путешествия",
|
||||
"discover.category.university": "Университет",
|
||||
"feed_view_type.articles": "Статьи",
|
||||
"feed_view_type.audios": "Аудио",
|
||||
"feed_view_type.notifications": "Уведомления",
|
||||
"feed_view_type.pictures": "Картинки",
|
||||
"feed_view_type.social_media": "Социальные сети",
|
||||
"feed_view_type.videos": "Видео",
|
||||
"ok": "ОК",
|
||||
"quantifier.piece": "",
|
||||
"retry": "Повторить попытку",
|
||||
|
|
@ -23,10 +52,13 @@
|
|||
"words.edit": "Редактировать",
|
||||
"words.entry": "Запись",
|
||||
"words.expand": "Расширить",
|
||||
"words.feeds": "Каналы",
|
||||
"words.follow": "Следовать",
|
||||
"words.id": "ID",
|
||||
"words.inbox": "Почтовый ящик",
|
||||
"words.items_one": "Элемент",
|
||||
"words.items_other": "Элементы",
|
||||
"words.lists": "Списки",
|
||||
"words.local": "локальный",
|
||||
"words.manage": "Управлять",
|
||||
"words.record": "запись",
|
||||
|
|
@ -38,6 +70,8 @@
|
|||
"words.result_other": "результаты",
|
||||
"words.rsshub": "RSSHub",
|
||||
"words.save": "Сохранить",
|
||||
"words.search": "Поиск",
|
||||
"words.starred": "Избранное",
|
||||
"words.submit": "Отправить",
|
||||
"words.update": "Обновить",
|
||||
"words.which.all": "Все"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
"cancel": "İptal",
|
||||
"close": "Kapat",
|
||||
"confirm": "Onayla",
|
||||
"feed_view_type.articles": "Makaleler",
|
||||
"feed_view_type.audios": "Sesler",
|
||||
"feed_view_type.notifications": "Bildirimler",
|
||||
"feed_view_type.pictures": "Resimler",
|
||||
"feed_view_type.social_media": "Sosyal Medya",
|
||||
"feed_view_type.videos": "Videolar",
|
||||
"ok": "Tamam",
|
||||
"quantifier.piece": "",
|
||||
"space": " ",
|
||||
|
|
@ -17,9 +23,11 @@
|
|||
"words.create": "Oluştur",
|
||||
"words.edit": "Düzenle",
|
||||
"words.entry": "Giriş",
|
||||
"words.feeds": "Beslemeler",
|
||||
"words.id": "ID",
|
||||
"words.items_one": "Öğe",
|
||||
"words.items_other": "Öğeler",
|
||||
"words.lists": "Listeler",
|
||||
"words.local": "yerel",
|
||||
"words.manage": "Yönet",
|
||||
"words.record": "kayıt",
|
||||
|
|
@ -28,6 +36,8 @@
|
|||
"words.result": "sonuç",
|
||||
"words.result_one": "sonuç",
|
||||
"words.result_other": "sonuçlar",
|
||||
"words.search": "Ara",
|
||||
"words.starred": "Yıldızlı",
|
||||
"words.submit": "Gönder",
|
||||
"words.update": "Güncelle",
|
||||
"words.which.all": "Tümü"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,35 @@
|
|||
"cancel": "取消",
|
||||
"close": "关闭",
|
||||
"confirm": "确认",
|
||||
"discover.category.all": "全部",
|
||||
"discover.category.anime": "二次元",
|
||||
"discover.category.bbs": "论坛",
|
||||
"discover.category.blog": "博客",
|
||||
"discover.category.design": "设计",
|
||||
"discover.category.finance": "金融",
|
||||
"discover.category.forecast": "预报预警",
|
||||
"discover.category.game": "游戏",
|
||||
"discover.category.government": "政务消息",
|
||||
"discover.category.journal": "科学期刊",
|
||||
"discover.category.live": "直播",
|
||||
"discover.category.multimedia": "音视频",
|
||||
"discover.category.new-media": "新媒体",
|
||||
"discover.category.picture": "图片",
|
||||
"discover.category.program-update": "程序更新",
|
||||
"discover.category.programming": "编程",
|
||||
"discover.category.reading": "阅读",
|
||||
"discover.category.shopping": "购物",
|
||||
"discover.category.social-media": "社交媒体",
|
||||
"discover.category.study": "学习",
|
||||
"discover.category.traditional-media": "传统媒体",
|
||||
"discover.category.travel": "出行旅游",
|
||||
"discover.category.university": "大学通知",
|
||||
"feed_view_type.articles": "文章",
|
||||
"feed_view_type.audios": "音频",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "图片",
|
||||
"feed_view_type.social_media": "社交媒体",
|
||||
"feed_view_type.videos": "视频",
|
||||
"ok": "好",
|
||||
"quantifier.piece": "条",
|
||||
"retry": "重试",
|
||||
|
|
@ -24,10 +53,13 @@
|
|||
"words.edit": "编辑",
|
||||
"words.entry": "条目",
|
||||
"words.expand": "展开",
|
||||
"words.feeds": "订阅源",
|
||||
"words.follow": "关注",
|
||||
"words.id": "ID",
|
||||
"words.inbox": "收件箱",
|
||||
"words.items_one": "内容",
|
||||
"words.items_other": "内容",
|
||||
"words.lists": "列表",
|
||||
"words.local": "本地",
|
||||
"words.manage": "管理",
|
||||
"words.record": "记录",
|
||||
|
|
@ -39,6 +71,8 @@
|
|||
"words.result_other": "结果",
|
||||
"words.rsshub": "RSSHub",
|
||||
"words.save": "保存",
|
||||
"words.search": "搜索",
|
||||
"words.starred": "收藏",
|
||||
"words.submit": "提交",
|
||||
"words.update": "更新",
|
||||
"words.which.all": "全部"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,35 @@
|
|||
"cancel": "取消",
|
||||
"close": "關閉",
|
||||
"confirm": "確認",
|
||||
"discover.category.all": "全部",
|
||||
"discover.category.anime": "ACG",
|
||||
"discover.category.bbs": "討論區",
|
||||
"discover.category.blog": "博客",
|
||||
"discover.category.design": "設計",
|
||||
"discover.category.finance": "財經",
|
||||
"discover.category.forecast": "預測",
|
||||
"discover.category.game": "遊戲",
|
||||
"discover.category.government": "政府",
|
||||
"discover.category.journal": "科學期刊",
|
||||
"discover.category.live": "直播",
|
||||
"discover.category.multimedia": "多媒體",
|
||||
"discover.category.new-media": "新媒體",
|
||||
"discover.category.picture": "圖片",
|
||||
"discover.category.program-update": "應用程式更新",
|
||||
"discover.category.programming": "程式設計",
|
||||
"discover.category.reading": "閱讀",
|
||||
"discover.category.shopping": "購物",
|
||||
"discover.category.social-media": "社交媒體",
|
||||
"discover.category.study": "學習",
|
||||
"discover.category.traditional-media": "新聞",
|
||||
"discover.category.travel": "旅遊",
|
||||
"discover.category.university": "大學",
|
||||
"feed_view_type.articles": "文章",
|
||||
"feed_view_type.audios": "音訊",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "圖片",
|
||||
"feed_view_type.social_media": "社交媒體",
|
||||
"feed_view_type.videos": "影片",
|
||||
"ok": "確定",
|
||||
"quantifier.piece": "",
|
||||
"retry": "重試",
|
||||
|
|
@ -24,10 +53,13 @@
|
|||
"words.edit": "編輯",
|
||||
"words.entry": "條目",
|
||||
"words.expand": "展開",
|
||||
"words.feeds": "訂閱源",
|
||||
"words.follow": "追隨",
|
||||
"words.id": "ID",
|
||||
"words.inbox": "收件匣",
|
||||
"words.items_one": "項目",
|
||||
"words.items_other": "項目",
|
||||
"words.lists": "清單",
|
||||
"words.local": "本地",
|
||||
"words.manage": "管理",
|
||||
"words.record": "記錄",
|
||||
|
|
@ -39,6 +71,8 @@
|
|||
"words.result_other": "結果",
|
||||
"words.rsshub": "RSSHub",
|
||||
"words.save": "儲存",
|
||||
"words.search": "搜尋",
|
||||
"words.starred": "收藏",
|
||||
"words.submit": "提交",
|
||||
"words.update": "更新",
|
||||
"words.which.all": "全部"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,35 @@
|
|||
"cancel": "取消",
|
||||
"close": "關閉",
|
||||
"confirm": "確認",
|
||||
"discover.category.all": "全部",
|
||||
"discover.category.anime": "動漫",
|
||||
"discover.category.bbs": "論壇",
|
||||
"discover.category.blog": "部落格",
|
||||
"discover.category.design": "設計",
|
||||
"discover.category.finance": "金融",
|
||||
"discover.category.forecast": "預報預警",
|
||||
"discover.category.game": "遊戲",
|
||||
"discover.category.government": "政府資訊",
|
||||
"discover.category.journal": "科學期刊",
|
||||
"discover.category.live": "直播",
|
||||
"discover.category.multimedia": "多媒體",
|
||||
"discover.category.new-media": "新媒體",
|
||||
"discover.category.picture": "圖片",
|
||||
"discover.category.program-update": "程式更新",
|
||||
"discover.category.programming": "程式設計",
|
||||
"discover.category.reading": "閱讀",
|
||||
"discover.category.shopping": "購物",
|
||||
"discover.category.social-media": "社交媒體",
|
||||
"discover.category.study": "學習",
|
||||
"discover.category.traditional-media": "傳統媒體",
|
||||
"discover.category.travel": "出行旅遊",
|
||||
"discover.category.university": "大學資訊",
|
||||
"feed_view_type.articles": "文章",
|
||||
"feed_view_type.audios": "音訊",
|
||||
"feed_view_type.notifications": "通知",
|
||||
"feed_view_type.pictures": "圖片",
|
||||
"feed_view_type.social_media": "社交媒體",
|
||||
"feed_view_type.videos": "影片",
|
||||
"ok": "確定",
|
||||
"quantifier.piece": "條",
|
||||
"retry": "重試",
|
||||
|
|
@ -23,10 +52,13 @@
|
|||
"words.edit": "編輯",
|
||||
"words.entry": "條目",
|
||||
"words.expand": "展開",
|
||||
"words.feeds": "RSS 摘要",
|
||||
"words.follow": "跟隨",
|
||||
"words.id": "ID",
|
||||
"words.inbox": "收件匣",
|
||||
"words.items_one": "內容",
|
||||
"words.items_other": "內容",
|
||||
"words.lists": "列表",
|
||||
"words.local": "本地",
|
||||
"words.manage": "管理",
|
||||
"words.record": "記錄",
|
||||
|
|
@ -38,6 +70,8 @@
|
|||
"words.result_other": "結果",
|
||||
"words.rsshub": "RSSHub",
|
||||
"words.save": "儲存",
|
||||
"words.search": "搜尋",
|
||||
"words.starred": "收藏",
|
||||
"words.submit": "提交",
|
||||
"words.update": "更新",
|
||||
"words.which.all": "全部"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "ملف {{name}} الشخصي",
|
||||
"profile.uncategorized_feeds": "الخلاصات غير المصنفة",
|
||||
"tabs.discover": "اكتشف",
|
||||
"tabs.home": "الرئيسية",
|
||||
"tabs.settings": "الإعدادات",
|
||||
"tabs.subscriptions": "الاشتراكات"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "ملف {{name}} الشخصي",
|
||||
"profile.uncategorized_feeds": "الخلاصات غير المصنفة",
|
||||
"tabs.discover": "اكتشف",
|
||||
"tabs.home": "الرئيسية",
|
||||
"tabs.settings": "الإعدادات",
|
||||
"tabs.subscriptions": "الاشتراكات"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "ملف {{name}} الشخصي",
|
||||
"profile.uncategorized_feeds": "الخلاصات غير المصنفة",
|
||||
"tabs.discover": "اكتشف",
|
||||
"tabs.home": "الرئيسية",
|
||||
"tabs.settings": "الإعدادات",
|
||||
"tabs.subscriptions": "الاشتراكات"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "ملف {{name}} الشخصي",
|
||||
"profile.uncategorized_feeds": "الخلاصات غير المصنفة",
|
||||
"tabs.discover": "اكتشف",
|
||||
"tabs.home": "الرئيسية",
|
||||
"tabs.settings": "الإعدادات",
|
||||
"tabs.subscriptions": "الاشتراكات"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "ملف {{name}} الشخصي",
|
||||
"profile.uncategorized_feeds": "الخلاصات غير المصنفة",
|
||||
"tabs.discover": "اكتشف",
|
||||
"tabs.home": "الرئيسية",
|
||||
"tabs.settings": "الإعدادات",
|
||||
"tabs.subscriptions": "الاشتراكات"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "ملف {{name}} الشخصي",
|
||||
"profile.uncategorized_feeds": "الخلاصات غير المصنفة",
|
||||
"tabs.discover": "اكتشف",
|
||||
"tabs.home": "الرئيسية",
|
||||
"tabs.settings": "الإعدادات",
|
||||
"tabs.subscriptions": "الاشتراكات"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "{{name}}s Profil",
|
||||
"profile.uncategorized_feeds": "Unkategorisierte Feeds",
|
||||
"tabs.discover": "Entdecken",
|
||||
"tabs.home": "Startseite",
|
||||
"tabs.settings": "Einstellungen",
|
||||
"tabs.subscriptions": "Abonnements"
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"profile.title": "{{name}}'s Profile",
|
||||
"profile.uncategorized_feeds": "Uncategorized feeds",
|
||||
"tabs.discover": "Discover",
|
||||
"tabs.home": "Home",
|
||||
"tabs.settings": "Settings",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "Perfil de {{name}}",
|
||||
"profile.uncategorized_feeds": "Feeds sin categorizar",
|
||||
"tabs.discover": "Descubrir",
|
||||
"tabs.home": "Inicio",
|
||||
"tabs.settings": "Configuraciones",
|
||||
"tabs.subscriptions": "Suscripciones"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "{{name}}n profiili",
|
||||
"profile.uncategorized_feeds": "Luokittelemattomat syötteet",
|
||||
"tabs.discover": "Löydä",
|
||||
"tabs.home": "Koti",
|
||||
"tabs.settings": "Asetukset",
|
||||
"tabs.subscriptions": "Tilaukset"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "Profil de {{name}}",
|
||||
"profile.uncategorized_feeds": "Flux non catégorisés",
|
||||
"tabs.discover": "Découvrir",
|
||||
"tabs.home": "Accueil",
|
||||
"tabs.settings": "Paramètres",
|
||||
"tabs.subscriptions": "Abonnements"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "Profilo di {{name}}",
|
||||
"profile.uncategorized_feeds": "Feed non categorizzati",
|
||||
"tabs.discover": "Scopri",
|
||||
"tabs.home": "Home",
|
||||
"tabs.settings": "Impostazioni",
|
||||
"tabs.subscriptions": "Abbonamenti"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "{{name}}のプロフィール",
|
||||
"profile.uncategorized_feeds": "未分類のフィード",
|
||||
"tabs.discover": "発見",
|
||||
"tabs.home": "ホーム",
|
||||
"tabs.settings": "設定",
|
||||
"tabs.subscriptions": "購読"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "{{name}}의 프로필",
|
||||
"profile.uncategorized_feeds": "분류되지 않은 피드",
|
||||
"tabs.discover": "발견",
|
||||
"tabs.home": "홈",
|
||||
"tabs.settings": "설정",
|
||||
"tabs.subscriptions": "구독"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "Perfil de {{name}}",
|
||||
"profile.uncategorized_feeds": "Feeds não categorizados",
|
||||
"tabs.discover": "Descobrir",
|
||||
"tabs.home": "Início",
|
||||
"tabs.settings": "Configurações",
|
||||
"tabs.subscriptions": "Assinaturas"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "Профиль {{name}}",
|
||||
"profile.uncategorized_feeds": "Некатегоризированные ленты",
|
||||
"tabs.discover": "Открыть",
|
||||
"tabs.home": "Главная",
|
||||
"tabs.settings": "Настройки",
|
||||
"tabs.subscriptions": "Подписки"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "{{name}}'nin Profili",
|
||||
"profile.uncategorized_feeds": "Kategorize edilmemiş beslemeler",
|
||||
"tabs.discover": "Keşfet",
|
||||
"tabs.home": "Ana Sayfa",
|
||||
"tabs.settings": "Ayarlar",
|
||||
"tabs.subscriptions": "Abonelikler"
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"profile.title": "{{name}}的个人资料",
|
||||
"profile.uncategorized_feeds": "未分类的订阅源",
|
||||
"tabs.discover": "发现",
|
||||
"tabs.home": "首页",
|
||||
"tabs.settings": "设置",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "{{name}}的個人資料",
|
||||
"profile.uncategorized_feeds": "未分類的訂閱源",
|
||||
"tabs.discover": "探索",
|
||||
"tabs.home": "主頁",
|
||||
"tabs.settings": "設定",
|
||||
"tabs.subscriptions": "訂閱"
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"profile.title": "{{name}}的個人資料",
|
||||
"profile.uncategorized_feeds": "未分類的訂閱源",
|
||||
"tabs.discover": "探索",
|
||||
"tabs.home": "首頁",
|
||||
"tabs.settings": "設定",
|
||||
"tabs.subscriptions": "訂閱"
|
||||
}
|
||||
|
|
@ -359,6 +359,7 @@
|
|||
"rsshub.useModal.title": "RSSHub Instance",
|
||||
"rsshub.useModal.useWith": "Use with {{amount}} <Power />",
|
||||
"titles.about": "About",
|
||||
"titles.account": "Account",
|
||||
"titles.actions": "Actions",
|
||||
"titles.appearance": "Appearance",
|
||||
"titles.data_control": "Data Control",
|
||||
|
|
@ -367,9 +368,12 @@
|
|||
"titles.integration": "Integration",
|
||||
"titles.invitations": "Invitations",
|
||||
"titles.lists": "Lists",
|
||||
"titles.notifications": "Notifications",
|
||||
"titles.power": "Power",
|
||||
"titles.privacy": "Privacy",
|
||||
"titles.profile": "Profile",
|
||||
"titles.shortcuts": "Shortcuts",
|
||||
"titles.sign_out": "Sign Out",
|
||||
"wallet.address.title": "Your Address",
|
||||
"wallet.balance.activePoints": "Active Points",
|
||||
"wallet.balance.dailyReward": "Your Daily Reward",
|
||||
|
|
|
|||
|
|
@ -350,6 +350,7 @@
|
|||
"rsshub.useModal.title": "RSSHub 实例",
|
||||
"rsshub.useModal.useWith": "使用 {{amount}} <Power />",
|
||||
"titles.about": "关于",
|
||||
"titles.account": "账户",
|
||||
"titles.actions": "自动化",
|
||||
"titles.appearance": "外观",
|
||||
"titles.data_control": "数据控制",
|
||||
|
|
@ -358,9 +359,12 @@
|
|||
"titles.integration": "集成",
|
||||
"titles.invitations": "邀请",
|
||||
"titles.lists": "列表",
|
||||
"titles.notifications": "通知",
|
||||
"titles.power": "Power",
|
||||
"titles.privacy": "隐私",
|
||||
"titles.profile": "个人资料",
|
||||
"titles.shortcuts": "快捷键",
|
||||
"titles.sign_out": "登出",
|
||||
"wallet.address.title": "地址",
|
||||
"wallet.balance.activePoints": "活跃度",
|
||||
"wallet.balance.dailyReward": "每日奖励",
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@ import * as React from "react"
|
|||
|
||||
import { FeedViewType } from "./enums"
|
||||
|
||||
interface ViewDefinition {
|
||||
name: string
|
||||
export interface ViewDefinition {
|
||||
name:
|
||||
| "feed_view_type.articles"
|
||||
| "feed_view_type.audios"
|
||||
| "feed_view_type.notifications"
|
||||
| "feed_view_type.pictures"
|
||||
| "feed_view_type.social_media"
|
||||
| "feed_view_type.videos"
|
||||
icon: React.JSX.Element
|
||||
className: string
|
||||
peerClassName: string
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
|
||||
const sourceDir = "./locales/app"
|
||||
const targetDir = "./locales/common"
|
||||
const keysToCopy: string[] = [
|
||||
"feed_view_type.articles",
|
||||
"feed_view_type.audios",
|
||||
"feed_view_type.notifications",
|
||||
"feed_view_type.pictures",
|
||||
"feed_view_type.social_media",
|
||||
"feed_view_type.videos",
|
||||
// kept the duplicate keys in locales/app
|
||||
"words.starred",
|
||||
"words.inbox",
|
||||
"words.feeds",
|
||||
"words.lists",
|
||||
"words.search",
|
||||
"discover.category.all",
|
||||
"discover.category.anime",
|
||||
"discover.category.bbs",
|
||||
"discover.category.blog",
|
||||
"discover.category.design",
|
||||
"discover.category.finance",
|
||||
"discover.category.forecast",
|
||||
"discover.category.game",
|
||||
"discover.category.government",
|
||||
"discover.category.journal",
|
||||
"discover.category.live",
|
||||
"discover.category.multimedia",
|
||||
"discover.category.new-media",
|
||||
"discover.category.picture",
|
||||
"discover.category.program-update",
|
||||
"discover.category.programming",
|
||||
"discover.category.reading",
|
||||
"discover.category.shopping",
|
||||
"discover.category.social-media",
|
||||
"discover.category.study",
|
||||
"discover.category.traditional-media",
|
||||
"discover.category.travel",
|
||||
"discover.category.university",
|
||||
]
|
||||
|
||||
const copyTranslations = (sourceDir: string, targetDir: string) => {
|
||||
const sourceFiles = fs.readdirSync(sourceDir)
|
||||
|
||||
sourceFiles.forEach((file) => {
|
||||
const sourceFilePath = path.join(sourceDir, file)
|
||||
const targetFilePath = path.join(targetDir, file)
|
||||
|
||||
if (fs.statSync(sourceFilePath).isDirectory()) {
|
||||
// Recursively copy translations from subdirectories
|
||||
copyTranslations(sourceFilePath, targetFilePath)
|
||||
} else if (path.extname(file) === ".json") {
|
||||
const sourceContent = JSON.parse(fs.readFileSync(sourceFilePath, "utf-8"))
|
||||
const targetContent = fs.existsSync(targetFilePath)
|
||||
? JSON.parse(fs.readFileSync(targetFilePath, "utf-8"))
|
||||
: {}
|
||||
|
||||
keysToCopy.forEach((key) => {
|
||||
if (sourceContent[key] && !targetContent[key]) {
|
||||
targetContent[key] = sourceContent[key]
|
||||
}
|
||||
})
|
||||
|
||||
fs.writeFileSync(targetFilePath, `${JSON.stringify(targetContent, null, 2)}\n`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
copyTranslations(sourceDir, targetDir)
|
||||
Loading…
Reference in New Issue