From 7efa6aa96a97a659837b35e174a6432d2913994a Mon Sep 17 00:00:00 2001 From: Stephen Zhou <38493346+hyoban@users.noreply.github.com> Date: Thu, 3 Apr 2025 12:25:54 +0800 Subject: [PATCH] feat(mobile): translation for operation (#3396) --- .../components/ui/image/ImageContextMenu.tsx | 8 +++- apps/mobile/src/lib/dialog.tsx | 5 ++- .../mobile/src/modules/context-menu/entry.tsx | 12 ++++-- .../mobile/src/modules/context-menu/feeds.tsx | 25 ++++++----- .../mobile/src/modules/context-menu/lists.tsx | 14 ++++--- .../mobile/src/modules/context-menu/video.tsx | 12 ++++-- .../modules/dialogs/MarkAllAsReadDialog.tsx | 8 ++-- .../EntryContentHeaderRightActions.tsx | 8 ++-- .../screen/TimelineSelectorProvider.tsx | 4 +- .../TimelineViewSelectorContextMenu.tsx | 4 +- apps/mobile/src/modules/screen/action.tsx | 18 ++++++-- locales/mobile/default/ar-DZ.json | 12 ++++++ locales/mobile/default/ar-IQ.json | 12 ++++++ locales/mobile/default/ar-KW.json | 12 ++++++ locales/mobile/default/ar-MA.json | 12 ++++++ locales/mobile/default/ar-SA.json | 12 ++++++ locales/mobile/default/ar-TN.json | 12 ++++++ locales/mobile/default/de.json | 12 ++++++ locales/mobile/default/en.json | 19 +++++++++ locales/mobile/default/es.json | 12 ++++++ locales/mobile/default/fi.json | 12 ++++++ locales/mobile/default/fr.json | 12 ++++++ locales/mobile/default/it.json | 12 ++++++ locales/mobile/default/ja.json | 13 ++++++ locales/mobile/default/ko.json | 13 ++++++ locales/mobile/default/pt.json | 12 ++++++ locales/mobile/default/ru.json | 13 ++++++ locales/mobile/default/tr.json | 12 ++++++ locales/mobile/default/zh-CN.json | 19 +++++++++ locales/mobile/default/zh-HK.json | 13 ++++++ locales/mobile/default/zh-TW.json | 13 ++++++ package.json | 2 +- scripts/copy-translation.ts | 42 +++++++++++++------ 33 files changed, 368 insertions(+), 53 deletions(-) diff --git a/apps/mobile/src/components/ui/image/ImageContextMenu.tsx b/apps/mobile/src/components/ui/image/ImageContextMenu.tsx index ecf6f6b0e..4e161b018 100644 --- a/apps/mobile/src/components/ui/image/ImageContextMenu.tsx +++ b/apps/mobile/src/components/ui/image/ImageContextMenu.tsx @@ -6,6 +6,7 @@ import { saveToLibraryAsync } from "expo-media-library" import { shareAsync } from "expo-sharing" import type { PropsWithChildren } from "react" import { useRef } from "react" +import { useTranslation } from "react-i18next" import type { View } from "react-native" import { findNodeHandle, Image, Pressable } from "react-native" @@ -35,6 +36,7 @@ const getIOSNativeImageActions = () => { } export const ImageContextMenu = ({ imageUrl, entryId, children }: ImageContextMenuProps) => { + const { t } = useTranslation() const entry = useEntry(entryId!) const feedId = entry?.feedId const view = useSelectedView() @@ -105,7 +107,9 @@ export const ImageContextMenu = ({ imageUrl, entryId, children }: ImageContextMe name: isEntryStarred ? "star.slash" : "star", }} /> - {isEntryStarred ? "Unstar" : "Star"} + + {isEntryStarred ? t("operation.unstar") : t("operation.star")} + )} @@ -183,7 +187,7 @@ export const ImageContextMenu = ({ imageUrl, entryId, children }: ImageContextMe name: "square.and.arrow.up", }} /> - Share + {t("operation.share")} diff --git a/apps/mobile/src/lib/dialog.tsx b/apps/mobile/src/lib/dialog.tsx index 924e29e47..02c94c504 100644 --- a/apps/mobile/src/lib/dialog.tsx +++ b/apps/mobile/src/lib/dialog.tsx @@ -1,4 +1,5 @@ import { cn } from "@follow/utils" +import { t } from "i18next" import type { Dispatch, FC, ReactElement, ReactNode, SetStateAction } from "react" import { cloneElement, @@ -213,14 +214,14 @@ class DialogStatic { ) => { + const { t } = useTranslation() const entry = useEntry(id) const feedId = entry?.feedId const view = useSelectedView() @@ -62,7 +64,7 @@ export const EntryItemContextMenu = ({ id, children }: PropsWithChildren<{ id: s unreadSyncService.markEntryAsRead(id) }} > - Mark as Read + {t("operation.mark_as_read")} - {isEntryStarred ? "Unstar" : "Star"} + + {isEntryStarred ? t("operation.unstar") : t("operation.star")} + )} @@ -109,7 +113,7 @@ export const EntryItemContextMenu = ({ id, children }: PropsWithChildren<{ id: s name: "link", }} /> - Open Link + {t("operation.open_link")} )} @@ -130,7 +134,7 @@ export const EntryItemContextMenu = ({ id, children }: PropsWithChildren<{ id: s name: "square.and.arrow.up", }} /> - Share + {t("operation.share")} )} diff --git a/apps/mobile/src/modules/context-menu/feeds.tsx b/apps/mobile/src/modules/context-menu/feeds.tsx index 6efe0a861..2e2de4b4f 100644 --- a/apps/mobile/src/modules/context-menu/feeds.tsx +++ b/apps/mobile/src/modules/context-menu/feeds.tsx @@ -1,6 +1,7 @@ import { FeedViewType } from "@follow/constants" import type { FC, PropsWithChildren } from "react" import { useCallback, useMemo } from "react" +import { useTranslation } from "react-i18next" import type { ListRenderItemInfo } from "react-native" import { Alert, Clipboard, FlatList, View } from "react-native" @@ -25,6 +26,7 @@ export const SubscriptionFeedItemContextMenu: FC< view?: FeedViewType } > = ({ id, children, view }) => { + const { t } = useTranslation() const allCategories = useSubscriptionCategory(view) const navigation = useNavigation() return ( @@ -50,7 +52,7 @@ export const SubscriptionFeedItemContextMenu: FC< unreadSyncService.markFeedAsRead(id) }, [id])} > - Mark All As Read + {t("operation.mark_all_as_read")} - Add To Category + {t("operation.add_feeds_to_category")} @@ -126,7 +128,7 @@ export const SubscriptionFeedItemContextMenu: FC< - Edit + {t("operation.edit")} - Copy Link + {t("operation.copy_link")} { subscriptionSyncService.unsubscribe(id) }, }, ]) - }, [id])} + }, [id, t])} > - Unsubscribe + {t("operation.unfollow")} ) => { + const { t } = useTranslation() return ( {children} @@ -213,7 +216,7 @@ export const SubscriptionFeedCategoryContextMenu = ({ unreadSyncService.markFeedAsRead(feedIds) }, [feedIds])} > - Mark All As Read + {t("operation.mark_all_as_read")} - Change To Other View + {t("operation.change_to_other_view")} @@ -243,7 +246,7 @@ export const SubscriptionFeedCategoryContextMenu = ({ - Edit Category + {t("operation.rename_category")} - Delete Category + {t("operation.delete_category")} = ({ id, children }) => { + const { t } = useTranslation() const isOwnList = useIsOwnList(id) const actions = useMemo( () => [ isOwnList && { - title: "Edit", + title: t("operation.edit"), onSelect: () => { const list = getList(id) if (!list) return @@ -26,7 +28,7 @@ export const SubscriptionListItemContextMenu: FC< }, }, { - title: "Copy Link", + title: t("operation.copy_link"), onSelect: () => { const list = getList(id) if (!list) return @@ -35,16 +37,16 @@ export const SubscriptionListItemContextMenu: FC< }, }, { - title: "Unsubscribe", + title: t("operation.unfollow"), destructive: true, onSelect: () => { - Alert.alert("Unsubscribe", "Are you sure you want to unsubscribe?", [ + Alert.alert(t("operation.unfollow"), "Are you sure you want to unsubscribe?", [ { text: "Cancel", style: "cancel", }, { - text: "Unsubscribe", + text: t("operation.unfollow"), style: "destructive", onPress: () => { subscriptionSyncService.unsubscribe(id) @@ -54,7 +56,7 @@ export const SubscriptionListItemContextMenu: FC< }, }, ], - [id, isOwnList], + [id, isOwnList, t], ) return ( diff --git a/apps/mobile/src/modules/context-menu/video.tsx b/apps/mobile/src/modules/context-menu/video.tsx index c34ea2ea7..917ef0ffd 100644 --- a/apps/mobile/src/modules/context-menu/video.tsx +++ b/apps/mobile/src/modules/context-menu/video.tsx @@ -1,4 +1,5 @@ import type { PropsWithChildren } from "react" +import { useTranslation } from "react-i18next" import { Clipboard, Share } from "react-native" import { ContextMenu } from "@/src/components/ui/context-menu" @@ -14,6 +15,7 @@ type VideoContextMenuProps = PropsWithChildren<{ }> export const VideoContextMenu = ({ entryId, children }: VideoContextMenuProps) => { + const { t } = useTranslation() const entry = useEntry(entryId) const feedId = entry?.feedId const view = useSelectedView() @@ -50,7 +52,9 @@ export const VideoContextMenu = ({ entryId, children }: VideoContextMenuProps) = name: isEntryStarred ? "star.slash" : "star", }} /> - {isEntryStarred ? "Unstar" : "Star"} + + {isEntryStarred ? t("operation.unstar") : t("operation.star")} + )} @@ -66,7 +70,7 @@ export const VideoContextMenu = ({ entryId, children }: VideoContextMenuProps) = name: "link", }} /> - Open Link + {t("operation.open_link")} - Copy Link + {t("operation.copy_link")} - Share + {t("operation.share")} diff --git a/apps/mobile/src/modules/dialogs/MarkAllAsReadDialog.tsx b/apps/mobile/src/modules/dialogs/MarkAllAsReadDialog.tsx index 665be7bd1..88434a677 100644 --- a/apps/mobile/src/modules/dialogs/MarkAllAsReadDialog.tsx +++ b/apps/mobile/src/modules/dialogs/MarkAllAsReadDialog.tsx @@ -1,3 +1,5 @@ +import { t } from "i18next" +import { useTranslation } from "react-i18next" import { Text, View } from "react-native" import { CheckCircleCuteReIcon } from "@/src/icons/check_circle_cute_re" @@ -8,11 +10,12 @@ import { unreadSyncService } from "@/src/store/unread/store" import { useSelectedView } from "../screen/atoms" export const MarkAllAsReadDialog: DialogComponent = () => { + const { t } = useTranslation() const selectedView = useSelectedView() const ctx = Dialog.useDialogContext() return ( - Do you want to mark all items as read? + {t("operation.mark_all_as_read_confirm")} { ctx?.dismiss() @@ -26,8 +29,7 @@ export const MarkAllAsReadDialog: DialogComponent = () => { ) } -MarkAllAsReadDialog.title = "Mark All as Read" +MarkAllAsReadDialog.title = t("operation.mark_all_as_read") MarkAllAsReadDialog.id = "mark-all-as-read" -MarkAllAsReadDialog.title = "Mark All as Read" MarkAllAsReadDialog.headerIcon = diff --git a/apps/mobile/src/modules/entry-content/EntryContentHeaderRightActions.tsx b/apps/mobile/src/modules/entry-content/EntryContentHeaderRightActions.tsx index d9cdd8469..056e287b3 100644 --- a/apps/mobile/src/modules/entry-content/EntryContentHeaderRightActions.tsx +++ b/apps/mobile/src/modules/entry-content/EntryContentHeaderRightActions.tsx @@ -1,5 +1,6 @@ import { useAtom } from "jotai" import { useCallback, useEffect, useState } from "react" +import { useTranslation } from "react-i18next" import { Clipboard, Share, TouchableOpacity, View } from "react-native" import type { SharedValue } from "react-native-reanimated" import Animated, { interpolate, useAnimatedStyle } from "react-native-reanimated" @@ -56,6 +57,7 @@ const HeaderRightActionsImpl = ({ titleOpacityShareValue, isHeaderTitleVisible, }: HeaderRightActionsProps) => { + const { t } = useTranslation() const labelColor = useColor("label") const isStarred = useIsEntryStarred(entryId) const [extraActionContainerWidth, setExtraActionContainerWidth] = useState(0) @@ -150,7 +152,7 @@ const HeaderRightActionsImpl = ({ const actionItems = [ subscription && { key: "Star", - title: isStarred ? "Unstar" : "Star", + title: isStarred ? t("operation.unstar") : t("operation.star"), icon: isStarred ? : , iconIOS: { name: isStarred ? "star.fill" : "star", @@ -189,7 +191,7 @@ const HeaderRightActionsImpl = ({ }, { key: "Share", - title: "Share", + title: t("operation.share"), icon: , iconIOS: { name: "square.and.arrow.up" }, onPress: handleShare, @@ -257,7 +259,7 @@ const HeaderRightActionsImpl = ({ )} - Copy Link + {t("operation.copy_link")} diff --git a/apps/mobile/src/modules/screen/TimelineSelectorProvider.tsx b/apps/mobile/src/modules/screen/TimelineSelectorProvider.tsx index 81a232929..1ff949a55 100644 --- a/apps/mobile/src/modules/screen/TimelineSelectorProvider.tsx +++ b/apps/mobile/src/modules/screen/TimelineSelectorProvider.tsx @@ -1,5 +1,6 @@ import { env } from "@follow/shared/src/env" import { useMemo } from "react" +import { useTranslation } from "react-i18next" import { Share, View } from "react-native" import { useColor } from "react-native-uikit-colors" @@ -76,12 +77,13 @@ export function TimelineSelectorProvider({ } function FeedShareAction({ feedId }: { feedId?: string }) { + const { t } = useTranslation() const label = useColor("label") if (!feedId) return null return ( } onPress={() => { const feed = getFeed(feedId) diff --git a/apps/mobile/src/modules/screen/TimelineViewSelectorContextMenu.tsx b/apps/mobile/src/modules/screen/TimelineViewSelectorContextMenu.tsx index 2c41a1e91..cf661279b 100644 --- a/apps/mobile/src/modules/screen/TimelineViewSelectorContextMenu.tsx +++ b/apps/mobile/src/modules/screen/TimelineViewSelectorContextMenu.tsx @@ -1,5 +1,6 @@ import type { FeedViewType } from "@follow/constants" import type { FC, PropsWithChildren } from "react" +import { useTranslation } from "react-i18next" import { ContextMenu } from "@/src/components/ui/context-menu" import { unreadSyncService } from "@/src/store/unread/store" @@ -7,6 +8,7 @@ import { unreadSyncService } from "@/src/store/unread/store" export const TimelineViewSelectorContextMenu: FC< PropsWithChildren<{ type: string | undefined; viewId: FeedViewType | undefined }> > = ({ children, type, viewId }) => { + const { t } = useTranslation() if (type !== "view" || viewId === undefined) return children return ( @@ -19,7 +21,7 @@ export const TimelineViewSelectorContextMenu: FC< unreadSyncService.markViewAsRead(viewId) }} > - Mark as Read + {t("operation.mark_as_read")} {props.children} } onPress={() => { Dialog.show(MarkAllAsReadDialog) @@ -80,17 +82,27 @@ const useButtonVariant = ({ variant = "primary" }: HeaderActionButtonProps) => { return { size, color } } export const UnreadOnlyActionButton = ({ variant = "primary" }: HeaderActionButtonProps) => { + const { t } = useTranslation() const unreadOnly = useGeneralSettingKey("unreadOnly") const { size, color } = useButtonVariant({ variant }) return ( } selectedIcon={} onPress={() => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light) setGeneralSetting("unreadOnly", !unreadOnly) - toast.success(`Showing ${unreadOnly ? "all" : "unread"} entries`, { position: "bottom" }) + toast.success( + unreadOnly + ? t("operation.toggle_unread_only.show_all.success") + : t("operation.toggle_unread_only.show_unread_only.success"), + { position: "bottom" }, + ) }} selected={unreadOnly} overlay={false} diff --git a/locales/mobile/default/ar-DZ.json b/locales/mobile/default/ar-DZ.json index 22ea0f019..f7045ec36 100644 --- a/locales/mobile/default/ar-DZ.json +++ b/locales/mobile/default/ar-DZ.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "التغيير إلى عرض آخر", + "operation.copy_link": "نسخ الرابط", + "operation.delete_category": "حذف الفئة", + "operation.edit": "تحرير", + "operation.mark_all_as_read": "تحديد الكل كمقروء", + "operation.mark_all_as_read_confirm": "تأكيد تحديد الكل كمقروء؟", + "operation.mark_all_as_read_which": "هل تريد تحديد كمقروء؟", + "operation.mark_as_read": "تحديد كمقروء", + "operation.rename_category": "إعادة تسمية الفئة", + "operation.share": "مشاركة", + "operation.star": "تمييز بنجمة", + "operation.unfollow": "إلغاء المتابعة", "profile.title": "ملف {{name}} الشخصي", "profile.uncategorized_feeds": "الخلاصات غير المصنفة", "tabs.discover": "اكتشف", diff --git a/locales/mobile/default/ar-IQ.json b/locales/mobile/default/ar-IQ.json index 22ea0f019..fb6eaa1bf 100644 --- a/locales/mobile/default/ar-IQ.json +++ b/locales/mobile/default/ar-IQ.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "تغيير إلى عرض آخر", + "operation.copy_link": "نسخ الرابط", + "operation.delete_category": "حذف الفئة", + "operation.edit": "تحرير", + "operation.mark_all_as_read": "تحديد الكل كمقروء", + "operation.mark_all_as_read_confirm": "تأكيد تحديد الكل كمقروء؟", + "operation.mark_all_as_read_which": "تحديد كمقروء؟", + "operation.mark_as_read": "تحديد كمقروء", + "operation.rename_category": "إعادة تسمية الفئة", + "operation.share": "مشاركة", + "operation.star": "إضافة إلى المفضلة", + "operation.unfollow": "إلغاء المتابعة", "profile.title": "ملف {{name}} الشخصي", "profile.uncategorized_feeds": "الخلاصات غير المصنفة", "tabs.discover": "اكتشف", diff --git a/locales/mobile/default/ar-KW.json b/locales/mobile/default/ar-KW.json index 22ea0f019..5bca7addb 100644 --- a/locales/mobile/default/ar-KW.json +++ b/locales/mobile/default/ar-KW.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "التبديل إلى طريقة عرض أخرى", + "operation.copy_link": "نسخ الرابط", + "operation.delete_category": "حذف الفئة", + "operation.edit": "تحرير", + "operation.mark_all_as_read": "وضع علامة الكل كمقروء", + "operation.mark_all_as_read_confirm": "تأكيد وضع علامة الجميع كمقروء؟", + "operation.mark_all_as_read_which": "وضع علامة كمقروء؟", + "operation.mark_as_read": "وضع علامة كمقروء", + "operation.rename_category": "إعادة تسمية الفئة", + "operation.share": "مشاركة", + "operation.star": "تفضيل", + "operation.unfollow": "إلغاء المتابعة", "profile.title": "ملف {{name}} الشخصي", "profile.uncategorized_feeds": "الخلاصات غير المصنفة", "tabs.discover": "اكتشف", diff --git a/locales/mobile/default/ar-MA.json b/locales/mobile/default/ar-MA.json index 22ea0f019..0e009073c 100644 --- a/locales/mobile/default/ar-MA.json +++ b/locales/mobile/default/ar-MA.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "تغيير إلى عرض آخر", + "operation.copy_link": "نسخ الرابط", + "operation.delete_category": "حذف الفئة", + "operation.edit": "تعديل", + "operation.mark_all_as_read": "وضع علامة على الكل كمقروء", + "operation.mark_all_as_read_confirm": "تأكيد وضع علامة على الكل كمقروء؟", + "operation.mark_all_as_read_which": "وضع علامة على كمقروء؟", + "operation.mark_as_read": "وضع علامة كمقروء", + "operation.rename_category": "إعادة تسمية الفئة", + "operation.share": "مشاركة", + "operation.star": "إضافة إلى المفضلة", + "operation.unfollow": "إلغاء المتابعة", "profile.title": "ملف {{name}} الشخصي", "profile.uncategorized_feeds": "الخلاصات غير المصنفة", "tabs.discover": "اكتشف", diff --git a/locales/mobile/default/ar-SA.json b/locales/mobile/default/ar-SA.json index 22ea0f019..e99c2c663 100644 --- a/locales/mobile/default/ar-SA.json +++ b/locales/mobile/default/ar-SA.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "التغيير إلى عرض آخر", + "operation.copy_link": "نسخ الرابط", + "operation.delete_category": "حذف الفئة", + "operation.edit": "تحرير", + "operation.mark_all_as_read": "تمييز الكل كمقروء", + "operation.mark_all_as_read_confirm": "هل ترغب في تأكيد تمييز الكل كمقروء؟", + "operation.mark_all_as_read_which": "تمييز كمقروء؟", + "operation.mark_as_read": "تمييز كمقروء", + "operation.rename_category": "إعادة تسمية الفئة", + "operation.share": "مشاركة", + "operation.star": "تمييز", + "operation.unfollow": "إلغاء المتابعة", "profile.title": "ملف {{name}} الشخصي", "profile.uncategorized_feeds": "الخلاصات غير المصنفة", "tabs.discover": "اكتشف", diff --git a/locales/mobile/default/ar-TN.json b/locales/mobile/default/ar-TN.json index 22ea0f019..a886834cd 100644 --- a/locales/mobile/default/ar-TN.json +++ b/locales/mobile/default/ar-TN.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "التغيير إلى عرض آخر", + "operation.copy_link": "نسخ الرابط", + "operation.delete_category": "حذف الفئة", + "operation.edit": "تحرير", + "operation.mark_all_as_read": "وضع علامة على الكل كمقروء", + "operation.mark_all_as_read_confirm": "تأكيد وضع الجميع كمقروء؟", + "operation.mark_all_as_read_which": "وضع علامة كمقروء؟", + "operation.mark_as_read": "وضع علامة كمقروء", + "operation.rename_category": "إعادة تسمية الفئة", + "operation.share": "مشاركة", + "operation.star": "إضافة إلى المفضلة", + "operation.unfollow": "إلغاء المتابعة", "profile.title": "ملف {{name}} الشخصي", "profile.uncategorized_feeds": "الخلاصات غير المصنفة", "tabs.discover": "اكتشف", diff --git a/locales/mobile/default/de.json b/locales/mobile/default/de.json index bbf2b37c7..d95e1e61a 100644 --- a/locales/mobile/default/de.json +++ b/locales/mobile/default/de.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "Zu anderer Ansicht wechseln", + "operation.copy_link": "Link kopieren", + "operation.delete_category": "Kategorie löschen", + "operation.edit": "Bearbeiten", + "operation.mark_all_as_read": "Alles als gelesen markieren", + "operation.mark_all_as_read_confirm": "Möchten Sie alle als gelesen markieren?", + "operation.mark_all_as_read_which": " als gelesen markieren?", + "operation.mark_as_read": "Als gelesen markieren", + "operation.rename_category": "Kategorie umbenennen", + "operation.share": "Teilen", + "operation.star": "Favorisieren", + "operation.unfollow": "Entfolgen", "profile.title": "{{name}}s Profil", "profile.uncategorized_feeds": "Unkategorisierte Feeds", "tabs.discover": "Entdecken", diff --git a/locales/mobile/default/en.json b/locales/mobile/default/en.json index 33fcd2224..55c294913 100644 --- a/locales/mobile/default/en.json +++ b/locales/mobile/default/en.json @@ -1,4 +1,23 @@ { + "operation.add_feeds_to_category": "Move to Category", + "operation.change_to_other_view": "Switch to Another View", + "operation.copy_link": "Copy Link", + "operation.delete_category": "Delete Category", + "operation.edit": "Edit", + "operation.mark_all_as_read": "Mark all as read", + "operation.mark_all_as_read_confirm": "Confirm mark all as read?", + "operation.mark_all_as_read_which": "Mark as read?", + "operation.mark_as_read": "Mark as Read", + "operation.open_link": "Open Link", + "operation.rename_category": "Rename Category", + "operation.share": "Share", + "operation.star": "Star", + "operation.toggle_unread_only.show_all.label": "Show All", + "operation.toggle_unread_only.show_all.success": "Showing all entries", + "operation.toggle_unread_only.show_unread_only.label": "Show Unread Only", + "operation.toggle_unread_only.show_unread_only.success": "Showing unread entries only", + "operation.unfollow": "Unfollow", + "operation.unstar": "Unstar", "profile.title": "{{name}}'s Profile", "profile.uncategorized_feeds": "Uncategorized feeds", "tabs.discover": "Discover", diff --git a/locales/mobile/default/es.json b/locales/mobile/default/es.json index 017f6f1c5..1d1fc4d4b 100644 --- a/locales/mobile/default/es.json +++ b/locales/mobile/default/es.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "Cambiar a otra vista", + "operation.copy_link": "Copiar enlace", + "operation.delete_category": "Eliminar categoría", + "operation.edit": "Editar", + "operation.mark_all_as_read": "Marcar todo como leído", + "operation.mark_all_as_read_confirm": "¿Confirmar marcar todo como leído?", + "operation.mark_all_as_read_which": "¿Marcar como leído?", + "operation.mark_as_read": "Marcar como leído", + "operation.rename_category": "Renombrar categoría", + "operation.share": "Compartir", + "operation.star": "Agregar a favoritos", + "operation.unfollow": "Dejar de seguir", "profile.title": "Perfil de {{name}}", "profile.uncategorized_feeds": "Feeds sin categorizar", "tabs.discover": "Descubrir", diff --git a/locales/mobile/default/fi.json b/locales/mobile/default/fi.json index f823fa58e..e8f6e8675 100644 --- a/locales/mobile/default/fi.json +++ b/locales/mobile/default/fi.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "Vaihda toiseen näkymään", + "operation.copy_link": "Kopioi linkki", + "operation.delete_category": "Poista kategoria", + "operation.edit": "Muokkaa", + "operation.mark_all_as_read": "Merkitse kaikki luetuiksi", + "operation.mark_all_as_read_confirm": "Vahvista kaikki merkinnät luetuiksi?", + "operation.mark_all_as_read_which": "Merkitäänkö luetuksi?", + "operation.mark_as_read": "Merkitse luetuksi", + "operation.rename_category": "Nimeä kategoria uudelleen", + "operation.share": "Jaa", + "operation.star": "Tähtää", + "operation.unfollow": "Lopeta seuraaminen", "profile.title": "{{name}}n profiili", "profile.uncategorized_feeds": "Luokittelemattomat syötteet", "tabs.discover": "Löydä", diff --git a/locales/mobile/default/fr.json b/locales/mobile/default/fr.json index c405eec37..c8fc54262 100644 --- a/locales/mobile/default/fr.json +++ b/locales/mobile/default/fr.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "Changer pour une autre vue", + "operation.copy_link": "Copier le lien", + "operation.delete_category": "Supprimer la catégorie", + "operation.edit": "Éditer", + "operation.mark_all_as_read": "Tout marquer comme lu", + "operation.mark_all_as_read_confirm": "Confirmez que vous voulez tout marquer comme lu ?", + "operation.mark_all_as_read_which": "Marquer comme lu ?", + "operation.mark_as_read": "Marquer comme lu", + "operation.rename_category": "Renommer la catégorie", + "operation.share": "Partager", + "operation.star": "Mettre en favori", + "operation.unfollow": "Se désabonner", "profile.title": "Profil de {{name}}", "profile.uncategorized_feeds": "Flux non catégorisés", "tabs.discover": "Découvrir", diff --git a/locales/mobile/default/it.json b/locales/mobile/default/it.json index 580fd07fc..f376d7633 100644 --- a/locales/mobile/default/it.json +++ b/locales/mobile/default/it.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "Cambia ad altra visualizzazione", + "operation.copy_link": "Copia link", + "operation.delete_category": "Elimina categoria", + "operation.edit": "Modifica", + "operation.mark_all_as_read": "Segna tutto come letto", + "operation.mark_all_as_read_confirm": "Confermi di segnare tutto come letto?", + "operation.mark_all_as_read_which": "Segna come letto?", + "operation.mark_as_read": "Segna come letto", + "operation.rename_category": "Rinomina categoria", + "operation.share": "Condividi", + "operation.star": "Aggiungi ai preferiti", + "operation.unfollow": "Smetti di seguire", "profile.title": "Profilo di {{name}}", "profile.uncategorized_feeds": "Feed non categorizzati", "tabs.discover": "Scopri", diff --git a/locales/mobile/default/ja.json b/locales/mobile/default/ja.json index 0a0b31ad3..7eba4e24e 100644 --- a/locales/mobile/default/ja.json +++ b/locales/mobile/default/ja.json @@ -1,4 +1,17 @@ { + "operation.add_feeds_to_category": "カテゴリーに移動", + "operation.change_to_other_view": "他のビューに切り替え", + "operation.copy_link": "リンクをコピー", + "operation.delete_category": "カテゴリーを削除", + "operation.edit": "編集", + "operation.mark_all_as_read": "すべてを既読にする", + "operation.mark_all_as_read_confirm": "すべてを既読にしますか?", + "operation.mark_all_as_read_which": "を既読にしますか?", + "operation.mark_as_read": "既読にする", + "operation.rename_category": "カテゴリーをリネーム", + "operation.share": "共有", + "operation.star": "スター", + "operation.unfollow": "フォロー解除", "profile.title": "{{name}}のプロフィール", "profile.uncategorized_feeds": "未分類のフィード", "tabs.discover": "発見", diff --git a/locales/mobile/default/ko.json b/locales/mobile/default/ko.json index 1df463bf0..13cb5da5e 100644 --- a/locales/mobile/default/ko.json +++ b/locales/mobile/default/ko.json @@ -1,4 +1,17 @@ { + "operation.add_feeds_to_category": "카테고리로 이동", + "operation.change_to_other_view": "다른 보기로 변경", + "operation.copy_link": "링크 복사", + "operation.delete_category": "카테고리 삭제", + "operation.edit": "편집", + "operation.mark_all_as_read": "모두 읽음으로 표시", + "operation.mark_all_as_read_confirm": "모두 읽음으로 표시하시겠습니까?", + "operation.mark_all_as_read_which": "을 (를) 모두 읽음으로 표시하시겠습니까?", + "operation.mark_as_read": "읽음으로 표시", + "operation.rename_category": "카테고리 이름 변경", + "operation.share": "공유", + "operation.star": "별표", + "operation.unfollow": "언팔로우", "profile.title": "{{name}}의 프로필", "profile.uncategorized_feeds": "분류되지 않은 피드", "tabs.discover": "발견", diff --git a/locales/mobile/default/pt.json b/locales/mobile/default/pt.json index 29efabb9e..2c5b04587 100644 --- a/locales/mobile/default/pt.json +++ b/locales/mobile/default/pt.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "他のビューに切り替え", + "operation.copy_link": "リンクをコピー", + "operation.delete_category": "カテゴリーを削除", + "operation.edit": "編集", + "operation.mark_all_as_read": "すべてを既読にする", + "operation.mark_all_as_read_confirm": "すべてを既読にしますか?", + "operation.mark_all_as_read_which": "を既読にしますか?", + "operation.mark_as_read": "既読にする", + "operation.rename_category": "カテゴリーの名前を変更", + "operation.share": "共有", + "operation.star": "スター", + "operation.unfollow": "フォロー解除", "profile.title": "Perfil de {{name}}", "profile.uncategorized_feeds": "Feeds não categorizados", "tabs.discover": "Descobrir", diff --git a/locales/mobile/default/ru.json b/locales/mobile/default/ru.json index d6a2eec62..32973f26e 100644 --- a/locales/mobile/default/ru.json +++ b/locales/mobile/default/ru.json @@ -1,4 +1,17 @@ { + "operation.add_feeds_to_category": "Переместить в категорию", + "operation.change_to_other_view": "Изменить на другой вид", + "operation.copy_link": "Копировать ссылку", + "operation.delete_category": "Удалить категорию", + "operation.edit": "Редактировать", + "operation.mark_all_as_read": "Отметить все как прочитанное", + "operation.mark_all_as_read_confirm": "Подтвердить отметку всего как прочитанное?", + "operation.mark_all_as_read_which": "Отметить как прочитанное?", + "operation.mark_as_read": "Отметить как прочитанное", + "operation.rename_category": "Переименовать категорию", + "operation.share": "Поделиться", + "operation.star": "Добавить в избранное", + "operation.unfollow": "Отписаться", "profile.title": "Профиль {{name}}", "profile.uncategorized_feeds": "Некатегоризированные ленты", "tabs.discover": "Открыть", diff --git a/locales/mobile/default/tr.json b/locales/mobile/default/tr.json index f8938ad97..c19c224df 100644 --- a/locales/mobile/default/tr.json +++ b/locales/mobile/default/tr.json @@ -1,4 +1,16 @@ { + "operation.change_to_other_view": "Diğer görünüme geç", + "operation.copy_link": "Bağlantıyı kopyala", + "operation.delete_category": "Kategoriyi sil", + "operation.edit": "Düzenle", + "operation.mark_all_as_read": "Tümünü okundu olarak işaretle", + "operation.mark_all_as_read_confirm": "Tümünü okundu olarak işaretlemeyi onaylıyor musunuz?", + "operation.mark_all_as_read_which": " okundu olarak işaretlensin mi?", + "operation.mark_as_read": "Okundu olarak işaretle", + "operation.rename_category": "Kategoriyi yeniden adlandır", + "operation.share": "Paylaş", + "operation.star": "Yıldızla", + "operation.unfollow": "Takibi bırak", "profile.title": "{{name}}'nin Profili", "profile.uncategorized_feeds": "Kategorize edilmemiş beslemeler", "tabs.discover": "Keşfet", diff --git a/locales/mobile/default/zh-CN.json b/locales/mobile/default/zh-CN.json index 486d21278..991ca2026 100644 --- a/locales/mobile/default/zh-CN.json +++ b/locales/mobile/default/zh-CN.json @@ -1,4 +1,23 @@ { + "operation.add_feeds_to_category": "移动至分类", + "operation.change_to_other_view": "更改为其他视图", + "operation.copy_link": "复制链接", + "operation.delete_category": "删除分类", + "operation.edit": "编辑", + "operation.mark_all_as_read": "全部标记为已读", + "operation.mark_all_as_read_confirm": "确认将全部标记为已读?", + "operation.mark_all_as_read_which": "将 标记为已读?", + "operation.mark_as_read": "标记为已读", + "operation.open_link": "打开链接", + "operation.rename_category": "重命名分类", + "operation.share": "分享", + "operation.star": "收藏", + "operation.toggle_unread_only.show_all.label": "显示全部", + "operation.toggle_unread_only.show_all.success": "正在显示所有条目", + "operation.toggle_unread_only.show_unread_only.label": "仅显示未读", + "operation.toggle_unread_only.show_unread_only.success": "仅显示未读条目", + "operation.unfollow": "取消订阅", + "operation.unstar": "取消收藏", "profile.title": "{{name}}的个人资料", "profile.uncategorized_feeds": "未分类的订阅源", "tabs.discover": "发现", diff --git a/locales/mobile/default/zh-HK.json b/locales/mobile/default/zh-HK.json index 74b6c2b1d..5eb4f7c03 100644 --- a/locales/mobile/default/zh-HK.json +++ b/locales/mobile/default/zh-HK.json @@ -1,4 +1,17 @@ { + "operation.add_feeds_to_category": "移至分類", + "operation.change_to_other_view": "切換到其他視圖", + "operation.copy_link": "複製連結", + "operation.delete_category": "刪除分類", + "operation.edit": "編輯", + "operation.mark_all_as_read": "全部標記為已讀", + "operation.mark_all_as_read_confirm": "確定將所有標記為已讀?", + "operation.mark_all_as_read_which": "確定將 標記為已讀?", + "operation.mark_as_read": "標記為已讀", + "operation.rename_category": "重新命名分類", + "operation.share": "分享", + "operation.star": "收藏", + "operation.unfollow": "取消追隨", "profile.title": "{{name}}的個人資料", "profile.uncategorized_feeds": "未分類的訂閱源", "tabs.discover": "探索", diff --git a/locales/mobile/default/zh-TW.json b/locales/mobile/default/zh-TW.json index 55220fbd4..4d373364d 100644 --- a/locales/mobile/default/zh-TW.json +++ b/locales/mobile/default/zh-TW.json @@ -1,4 +1,17 @@ { + "operation.add_feeds_to_category": "新增 RSS 摘要到類別", + "operation.change_to_other_view": "切換到其他視圖", + "operation.copy_link": "複製連結", + "operation.delete_category": "刪除類別", + "operation.edit": "編輯", + "operation.mark_all_as_read": "全部標記為已讀", + "operation.mark_all_as_read_confirm": "確認將全部標記為已讀?", + "operation.mark_all_as_read_which": "將 標記為已讀?", + "operation.mark_as_read": "標記為已讀", + "operation.rename_category": "重新命名類別", + "operation.share": "分享", + "operation.star": "收藏", + "operation.unfollow": "取消跟隨", "profile.title": "{{name}} 的個人資料", "profile.uncategorized_feeds": "未分類的 RSS 摘要", "tabs.discover": "探索", diff --git a/package.json b/package.json index 53904aef6..2b75cae95 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "scripts": { "build:web": "turbo run Folo#build:web", - "dedupe:locales": "eslint --fix locales/**/*.json", + "dedupe:locales": "eslint --fix locales/**", "depcheck": "npx depcheck --quiet", "format": "prettier --write .", "format:check": "prettier --check .", diff --git a/scripts/copy-translation.ts b/scripts/copy-translation.ts index 3a86c260a..2bce91ade 100644 --- a/scripts/copy-translation.ts +++ b/scripts/copy-translation.ts @@ -1,20 +1,38 @@ import fs from "node:fs" import path from "node:path" -const sourceDir = "./locales/common" -const targetDir = "./locales/common" +const sourceDir = "./locales/app" +const targetDir = "./locales/mobile/default" const keysToCopy: string[] = [ - // // kept the duplicate keys in locales/app - // "words.starred", - // "words.inbox", - // "words.feeds", - // "words.lists", - // "words.search", - "cancel", - "close", - "confirm", + "sidebar.feed_column.context_menu.mark_as_read", + "entry_actions.star", + "entry_actions.share", + "mark_all_read_button.mark_all_as_read", + "sidebar.feed_column.context_menu.add_feeds_to_category", + "sidebar.feed_actions.edit", + "entry_actions.copy_link", + "sidebar.feed_actions.unfollow", + "sidebar.feed_column.context_menu.change_to_other_view", + "sidebar.feed_column.context_menu.rename_category", + "sidebar.feed_column.context_menu.delete_category", + "mark_all_read_button.confirm_mark_all", + "mark_all_read_button.confirm_mark_all_info", +] +const keysToPlace = [ + "operation.mark_as_read", + "operation.star", + "operation.share", + "operation.mark_all_as_read", + "operation.add_feeds_to_category", + "operation.edit", + "operation.copy_link", + "operation.unfollow", + "operation.change_to_other_view", + "operation.rename_category", + "operation.delete_category", + "operation.mark_all_as_read_which", + "operation.mark_all_as_read_confirm", ] -const keysToPlace = ["words.cancel", "words.close", "words.confirm"] const copyTranslations = (sourceDir: string, targetDir: string) => { const sourceFiles = fs.readdirSync(sourceDir)