From da84d9b2e1e0d63f46bc674a76791fd9e941a6ac Mon Sep 17 00:00:00 2001
From: yusakuw
Date: Sun, 23 Jan 2022 00:35:49 +0900
Subject: [PATCH 1/7] fix UI font for CJK
---
dist/article/article.css | 2 +-
dist/styles/global.css | 18 +++++++++++++++++-
src/scripts/models/app.ts | 14 +++++++++-----
src/scripts/settings.ts | 16 +++++++++++++---
4 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/dist/article/article.css b/dist/article/article.css
index 68e4977..4b94154 100644
--- a/dist/article/article.css
+++ b/dist/article/article.css
@@ -3,7 +3,7 @@
html,
body {
margin: 0;
- font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei",
+ font-family: "Segoe UI", "Source Han Sans Regular",
sans-serif;
}
body {
diff --git a/dist/styles/global.css b/dist/styles/global.css
index fa934eb..93abd44 100644
--- a/dist/styles/global.css
+++ b/dist/styles/global.css
@@ -49,12 +49,28 @@ body.darwin {
html,
body {
background-color: transparent;
- font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei",
+ font-family: "Segoe UI", "Source Han Sans Regular",
sans-serif;
height: 100%;
overflow: hidden;
margin: 0;
}
+body:lang(zh-CN) {
+ font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei",
+ sans-serif;
+}
+body:lang(zh-TW) {
+ font-family: "Segoe UI", "Source Han Sans TC Regular", "Microsoft JhengHei",
+ sans-serif;
+}
+body:lang(ja) {
+ font-family: "Segoe UI", "Source Han Sans JP Regular", "Yu Gothic UI",
+ sans-serif;
+}
+body:lang(ko) {
+ font-family: "Segoe UI", "Source Han Sans KR Regular", "Malgun Gothic",
+ sans-serif;
+}
body.win32,
body.linux {
background-color: var(--neutralLighterAlt);
diff --git a/src/scripts/models/app.ts b/src/scripts/models/app.ts
index bef0216..ab17bec 100644
--- a/src/scripts/models/app.ts
+++ b/src/scripts/models/app.ts
@@ -32,7 +32,7 @@ import {
selectAllArticles,
showItemFromId,
} from "./page"
-import { getCurrentLocale } from "../settings"
+import { getCurrentLocale, setThemeDefaultFont } from "../settings"
import locales from "../i18n/_locales"
import { SYNC_SERVICE, ServiceActionTypes } from "./service"
@@ -369,10 +369,14 @@ export interface InitIntlAction {
type: typeof INIT_INTL
locale: string
}
-export const initIntlDone = (locale: string): InitIntlAction => ({
- type: INIT_INTL,
- locale: locale,
-})
+export const initIntlDone = (locale: string): InitIntlAction => {
+ document.documentElement.lang = locale
+ setThemeDefaultFont(locale)
+ return {
+ type: INIT_INTL,
+ locale: locale,
+ }
+}
export function initIntl(): AppThunk> {
return dispatch => {
diff --git a/src/scripts/settings.ts b/src/scripts/settings.ts
index 45ee994..3bf83d0 100644
--- a/src/scripts/settings.ts
+++ b/src/scripts/settings.ts
@@ -5,13 +5,13 @@ import { ThemeSettings } from "../schema-types"
import intl from "react-intl-universal"
import { SourceTextDirection } from "./models/source"
-const lightTheme: IPartialTheme = {
+let lightTheme: IPartialTheme = {
defaultFontStyle: {
fontFamily:
- '"Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei", sans-serif',
+ '"Segoe UI", "Source Han Sans Regular", sans-serif',
},
}
-const darkTheme: IPartialTheme = {
+let darkTheme: IPartialTheme = {
...lightTheme,
palette: {
neutralLighterAlt: "#282828",
@@ -41,6 +41,16 @@ const darkTheme: IPartialTheme = {
},
}
+export function setThemeDefaultFont(locale: string) {
+ switch(locale) {
+ case "zh-CN": lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei", sans-serif'; break
+ case "zh-TW": lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans TC Regular", "Microsoft JhengHei", sans-serif'; break
+ case "ja": lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans JP Regular", "Yu Gothic UI", sans-serif'; break
+ case "ko": lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans KR Regular", "Malgun Gothic", sans-serif'; break
+ default: lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans Regular", sans-serif'
+ }
+ applyThemeSettings()
+}
export function setThemeSettings(theme: ThemeSettings) {
window.settings.setThemeSettings(theme)
applyThemeSettings()
From a73bc491dfe17b3612820b988b75349129121dba Mon Sep 17 00:00:00 2001
From: Yousef Javaherian
Date: Fri, 11 Mar 2022 02:40:03 +0330
Subject: [PATCH 2/7] title & snippet in card component now respect source text
dir attribute
---
package-lock.json | 10 +++++-----
src/components/cards/compact-card.tsx | 7 ++++++-
src/components/cards/default-card.tsx | 13 +++++++++++--
src/components/cards/highlights.tsx | 19 ++++++++++++++++++-
src/components/cards/list-card.tsx | 2 ++
src/components/cards/magazine-card.tsx | 2 ++
6 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 69ad249..6e9cf5c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,9 +8,6 @@
"name": "fluent-reader",
"version": "1.1.0",
"license": "BSD-3-Clause",
- "dependencies": {
- "font-list": "^1.4.2"
- },
"devDependencies": {
"@fluentui/react": "^7.126.2",
"@types/lovefield": "^2.1.3",
@@ -24,6 +21,7 @@
"electron-react-devtools": "^0.5.3",
"electron-store": "^5.2.0",
"electron-window-state": "^5.0.3",
+ "font-list": "^1.4.2",
"hard-source-webpack-plugin": "^0.13.1",
"html-webpack-plugin": "^4.3.0",
"js-md5": "^0.7.3",
@@ -4192,7 +4190,8 @@
"node_modules/font-list": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/font-list/-/font-list-1.4.2.tgz",
- "integrity": "sha512-vPekA+sinAymEkNHwnOse0D75phwNvH/E0z/mJSgGoCBVKy+rLZzd3HziYVwlII34bb0ZYOKBbM36s2bfCaR1A=="
+ "integrity": "sha512-vPekA+sinAymEkNHwnOse0D75phwNvH/E0z/mJSgGoCBVKy+rLZzd3HziYVwlII34bb0ZYOKBbM36s2bfCaR1A==",
+ "dev": true
},
"node_modules/for-in": {
"version": "1.0.2",
@@ -12739,7 +12738,8 @@
"font-list": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/font-list/-/font-list-1.4.2.tgz",
- "integrity": "sha512-vPekA+sinAymEkNHwnOse0D75phwNvH/E0z/mJSgGoCBVKy+rLZzd3HziYVwlII34bb0ZYOKBbM36s2bfCaR1A=="
+ "integrity": "sha512-vPekA+sinAymEkNHwnOse0D75phwNvH/E0z/mJSgGoCBVKy+rLZzd3HziYVwlII34bb0ZYOKBbM36s2bfCaR1A==",
+ "dev": true
},
"for-in": {
"version": "1.0.2",
diff --git a/src/components/cards/compact-card.tsx b/src/components/cards/compact-card.tsx
index 566bfdc..e7eb594 100644
--- a/src/components/cards/compact-card.tsx
+++ b/src/components/cards/compact-card.tsx
@@ -23,10 +23,15 @@ const CompactCard: React.FunctionComponent = props => (
text={props.item.title}
filter={props.filter}
title
+ dir={props.source.textDir}
/>
-
+
diff --git a/src/components/cards/default-card.tsx b/src/components/cards/default-card.tsx
index c4d08a8..9edb85f 100644
--- a/src/components/cards/default-card.tsx
+++ b/src/components/cards/default-card.tsx
@@ -25,10 +25,19 @@ const DefaultCard: React.FunctionComponent = props => (
) : null}
-
+
-
+
)
diff --git a/src/components/cards/highlights.tsx b/src/components/cards/highlights.tsx
index e790519..6be11f3 100644
--- a/src/components/cards/highlights.tsx
+++ b/src/components/cards/highlights.tsx
@@ -1,11 +1,13 @@
import * as React from "react"
import { validateRegex } from "../../scripts/utils"
import { FeedFilter, FilterType } from "../../scripts/models/feed"
+import { SourceTextDirection } from "../../scripts/models/source"
type HighlightsProps = {
text: string
filter: FeedFilter
title?: boolean
+ dir: SourceTextDirection
}
const Highlights: React.FunctionComponent = props => {
@@ -57,10 +59,25 @@ const Highlights: React.FunctionComponent = props => {
}
}
+ const testStyle = {
+ direction: "inherit",
+ writingMode: "inherit",
+ } as React.CSSProperties
+ if (props.dir === SourceTextDirection.RTL) {
+ testStyle.direction = "rtl"
+ } else if (props.dir === SourceTextDirection.Vertical) {
+ testStyle.writingMode = "vertical-rl"
+ }
return (
<>
{spans.map(([text, flag]) =>
- flag ? {text} : text
+ flag ? (
+
+ {text}
+
+ ) : (
+ {text}
+ )
)}
>
)
diff --git a/src/components/cards/list-card.tsx b/src/components/cards/list-card.tsx
index 5afa8e1..5707226 100644
--- a/src/components/cards/list-card.tsx
+++ b/src/components/cards/list-card.tsx
@@ -31,6 +31,7 @@ const ListCard: React.FunctionComponent = props => (
text={props.item.title}
filter={props.filter}
title
+ dir={props.source.textDir}
/>
{Boolean(props.viewConfigs & ViewConfigs.ShowSnippet) && (
@@ -38,6 +39,7 @@ const ListCard: React.FunctionComponent = props => (
)}
diff --git a/src/components/cards/magazine-card.tsx b/src/components/cards/magazine-card.tsx
index d38f675..7ecc3d9 100644
--- a/src/components/cards/magazine-card.tsx
+++ b/src/components/cards/magazine-card.tsx
@@ -28,12 +28,14 @@ const MagazineCard: React.FunctionComponent = props => (
text={props.item.title}
filter={props.filter}
title
+ dir={props.source.textDir}
/>
From 6fac29b4db42dbe63a900cce218d36713a85c011 Mon Sep 17 00:00:00 2001
From: Bruce Liu
Date: Wed, 8 Jun 2022 11:18:26 -0700
Subject: [PATCH 3/7] remove vertical rtl for cards
---
src/components/cards/highlights.tsx | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/components/cards/highlights.tsx b/src/components/cards/highlights.tsx
index 6be11f3..772a86e 100644
--- a/src/components/cards/highlights.tsx
+++ b/src/components/cards/highlights.tsx
@@ -7,7 +7,7 @@ type HighlightsProps = {
text: string
filter: FeedFilter
title?: boolean
- dir: SourceTextDirection
+ dir?: SourceTextDirection
}
const Highlights: React.FunctionComponent = props => {
@@ -61,12 +61,9 @@ const Highlights: React.FunctionComponent = props => {
const testStyle = {
direction: "inherit",
- writingMode: "inherit",
} as React.CSSProperties
if (props.dir === SourceTextDirection.RTL) {
testStyle.direction = "rtl"
- } else if (props.dir === SourceTextDirection.Vertical) {
- testStyle.writingMode = "vertical-rl"
}
return (
<>
From 1765ca67b2aa4025779653f55d4c2ac83ae50a4f Mon Sep 17 00:00:00 2001
From: nxblnd <52958704+nxblnd@users.noreply.github.com>
Date: Wed, 8 Jun 2022 21:20:53 +0300
Subject: [PATCH 4/7] Russian translation (#400)
* Added ru.json based on en-US.json
* Enabled ru translation
* Modified i18n readme
---
src/components/settings/app.tsx | 1 +
src/scripts/i18n/README.md | 1 +
src/scripts/i18n/_locales.ts | 2 +
src/scripts/i18n/ru.json | 241 ++++++++++++++++++++++++++++++++
4 files changed, 245 insertions(+)
create mode 100644 src/scripts/i18n/ru.json
diff --git a/src/components/settings/app.tsx b/src/components/settings/app.tsx
index a5c6f68..9ceec93 100644
--- a/src/components/settings/app.tsx
+++ b/src/components/settings/app.tsx
@@ -139,6 +139,7 @@ class AppTab extends React.Component {
{ key: "sv", text: "Svenska" },
{ key: "tr", text: "Türkçe" },
{ key: "uk", text: "Українська" },
+ { key: "ru", text: "Русский" },
{ key: "ko", text: "한글" },
{ key: "ja", text: "日本語" },
{ key: "zh-CN", text: "中文(简体)" },
diff --git a/src/scripts/i18n/README.md b/src/scripts/i18n/README.md
index 5cf0889..18d0301 100644
--- a/src/scripts/i18n/README.md
+++ b/src/scripts/i18n/README.md
@@ -19,5 +19,6 @@ Currently, Fluent Reader supports the following languages.
| it | Italiano | [@andrewasd](https://github.com/andrewasd) |
| pt-BR | Português do Brasil | [@fabianski7](https://github.com/fabianski7) |
| ko | 한글 | [@1drive](https://github.com/1drive) |
+| ru | Russian | [@nxblnd](https://github.com/nxblnd) |
Refer to the repo of [react-intl-universal](https://github.com/alibaba/react-intl-universal) to get started on internationalization.
diff --git a/src/scripts/i18n/_locales.ts b/src/scripts/i18n/_locales.ts
index 187ca82..229b6a2 100644
--- a/src/scripts/i18n/_locales.ts
+++ b/src/scripts/i18n/_locales.ts
@@ -10,6 +10,7 @@ import sv from "./sv.json"
import tr from "./tr.json"
import it from "./it.json"
import uk from "./uk.json"
+import ru from "./ru.json"
import pt_BR from "./pt-BR.json"
import fi_FI from "./fi-FI.json"
import ko from "./ko.json"
@@ -27,6 +28,7 @@ const locales = {
"tr": tr,
"it": it,
"uk": uk,
+ "ru": ru,
"pt-BR": pt_BR,
"fi-FI": fi_FI,
"ko": ko,
diff --git a/src/scripts/i18n/ru.json b/src/scripts/i18n/ru.json
new file mode 100644
index 0000000..64f53cd
--- /dev/null
+++ b/src/scripts/i18n/ru.json
@@ -0,0 +1,241 @@
+{
+ "allArticles": "Все статьи",
+ "add": "Добавить",
+ "create": "Создать",
+ "icon": "Иконка",
+ "name": "Название",
+ "openExternal": "Открыть внешней программой",
+ "emptyName": "Это поле не может быть пустым.",
+ "emptyField": "Это поле не может быть пустым.",
+ "edit": "Редактировать",
+ "delete": "Удалить",
+ "followSystem": "Как в системе",
+ "more": "Ещё",
+ "close": "Закрыть",
+ "search": "Поиск",
+ "loadMore": "Загрузить ещё",
+ "dangerButton": "Подтвердить {action}?",
+ "confirmMarkAll": "Вы действительно хотите отметить все статьи на этой странице прочитанными?",
+ "confirm": "Подтвердить",
+ "cancel": "Отмена",
+ "default": "По умолчанию",
+ "time": {
+ "now": "сейчас",
+ "m": "м",
+ "h": "ч",
+ "d": "д",
+ "minute": "{m, plural, =1 {# минута} other {# минут}}",
+ "hour": "{h, plural, =1 {# час} other {# часов}}",
+ "day": "{d, plural, =1 {# день} other {# дней}}"
+ },
+ "log": {
+ "empty": "Нет уведомлений",
+ "fetchFailure": "Не удалось загрузить из источника \"{name}\".",
+ "fetchSuccess": "Успешно {count, plural, =1 {получена # статья} other {получены # статей}}.",
+ "networkError": "Ошибка сети.",
+ "parseError": "Возникла ошибка при разборе XML.",
+ "syncFailure": "Не удалось синхронизировать с сервисом"
+ },
+ "nav": {
+ "menu": "Меню",
+ "refresh": "Обновить",
+ "markAllRead": "Отметить всё прочитанным",
+ "notifications": "Уведомления",
+ "view": "Вид",
+ "settings": "Настройки",
+ "minimize": "Свернуть",
+ "maximize": "Развернуть"
+ },
+ "menu": {
+ "close": "Закрыть меню",
+ "subscriptions": "Подписки"
+ },
+ "article": {
+ "error": "Не удалось загрузить статью.",
+ "reload": "Перезагрузить?",
+ "empty": "Нет статей",
+ "untitled": "(Без названия)",
+ "hide": "Спрятать статью",
+ "unhide": "Показать статью",
+ "markRead": "Отметить как прочитанное",
+ "markUnread": "Отметить как непрочитанное",
+ "markAbove": "Отметить выше как прочитанное",
+ "markBelow": "Отметить ниже как прочитанное",
+ "star": "В избранное",
+ "unstar": "Убрать из избранного",
+ "fontSize": "Размер шрифта",
+ "loadWebpage": "Загрузить веб-страницу",
+ "loadFull": "Загрузить полное содержимое",
+ "notify": "Уведомить, если получено в фоновом режиме",
+ "dontNotify": "Не уведомлять",
+ "textDir": "Направление текста",
+ "LTR": "Слева направо",
+ "RTL": "Справа налево",
+ "Vertical": "Вертикально",
+ "font": "Шрифт"
+ },
+ "context": {
+ "share": "Поделиться",
+ "read": "Читать",
+ "copyTitle": "Копировать заголовок",
+ "copyURL": "Копировать ссылку",
+ "copy": "Копировать",
+ "search": "Искать \"{text}\" в {engine}",
+ "view": "Вид",
+ "cardView": "Карточки",
+ "listView": "Список",
+ "magazineView": "Журнал",
+ "compactView": "Компактный",
+ "filter": "Фильтры",
+ "unreadOnly": "Только непрочитанные",
+ "starredOnly": "Только избранные",
+ "fullSearch": "Поиск по всему тексту",
+ "showHidden": "Показывать скрытые",
+ "manageSources": "Управление источниками",
+ "saveImageAs": "Сохранить изображение как …",
+ "copyImage": "Копировать изображение",
+ "copyImageURL": "Копировать ссылку на изображение",
+ "caseSensitive": "С учётом регистра",
+ "showCover": "Показать обложку",
+ "showSnippet": "Показать отрывок",
+ "fadeRead": "Высветлять прочитанные статьи"
+ },
+ "searchEngine": {
+ "name": "Поисковая система",
+ "google": "Google",
+ "bing": "Bing",
+ "baidu": "Baidu",
+ "duckduckgo": "DuckDuckGo"
+ },
+ "settings": {
+ "writeError": "Произошла ошибка при записи файла.",
+ "name": "Настройки",
+ "fetching": "Обновление источников. Пожалуйста, подождите.",
+ "exit": "Выйти из настроек",
+ "sources": "Источники",
+ "grouping": "Группы",
+ "rules": "Правила",
+ "service": "Сервисы",
+ "app": "Предпочтения",
+ "about": "О программе",
+ "version": "Версия",
+ "shortcuts": "Сочетания клавиш",
+ "openSource": "Открытый исходный код",
+ "feedback": "Обратная связь"
+ },
+ "sources": {
+ "serviceWarning": "Импортированные или добавленные здесь источники не будут синхронизированы с Вашим сервисом.",
+ "serviceManaged": "Этот источник управляется Вашим сервисом.",
+ "untitled": "Источник",
+ "errorAdd": "Возникла ошибка при добавлении источника.",
+ "errorParse": "Возникла ошибка при разборе OPML файла.",
+ "errorParseHint": "Пожалуйста, удостоверьтесь что файл не повреждён и использует кодировку UTF-8.",
+ "errorImport": "Ошибка импорта {count, plural, =1 {# источника} other {# источников}}.",
+ "exist": "Этот источник уже существует.",
+ "opmlFile": "OPML файл",
+ "name": "Название источника",
+ "editName": "Изменить название",
+ "fetchFrequency": "Ограничение частоты обновлений",
+ "unlimited": "Без ограничений",
+ "openTarget": "Метод открытия статей по умолчанию",
+ "delete": "Удалить источник",
+ "add": "Добавить источник",
+ "import": "Импорт",
+ "export": "Экспорт",
+ "rssText": "Полный текст RSS",
+ "loadWebpage": "Загрузить веб-страницу",
+ "inputUrl": "Введите URL",
+ "badIcon": "Недопустимая иконка",
+ "badUrl": "Недопустимый URL",
+ "deleteWarning": "Источник и все сохранённые статьи будут удалены.",
+ "selected": "Выберите источник",
+ "selectedMulti": "Выберите несколько источников"
+ },
+ "groups": {
+ "exist": "Эта группа уже существует.",
+ "type": "Тип",
+ "group": "Группа",
+ "source": "Источник",
+ "capacity": "Ёмкость",
+ "exitGroup": "Назад к группам",
+ "deleteSource": "Удалить из группы",
+ "sourceHint": "Перетаскивайте источники для изменения порядка.",
+ "create": "Создать группу",
+ "selectedGroup": "Выбранная группа",
+ "selectedSource": "Выбранный источник",
+ "enterName": "Введите название",
+ "editName": "Изменить название",
+ "deleteGroup": "Удалить группу",
+ "chooseGroup": "Выбрать группу",
+ "addToGroup": "Добавить в …",
+ "groupHint": "Сделайте двойной щелчок по группе для редактирования источников. Перетаскивайте для изменения порядка."
+ },
+ "rules": {
+ "intro": "Автоматически отмечать статьи или отправлять уведомления с помощью регулярных выражений.",
+ "help": "Узнать больше",
+ "source": "Источник",
+ "selectSource": "Выбрать источник",
+ "new": "Новое правило",
+ "if": "Если",
+ "then": "То",
+ "title": "Название",
+ "content": "Содержимое",
+ "fullSearch": "Название или содержимое",
+ "creator": "Автор",
+ "match": "совпадает",
+ "notMatch": "не совпадает",
+ "regex": "Регулярное выражение",
+ "badRegex": "Недопустимое регулярное выражение.",
+ "action": "Действия",
+ "selectAction": "Выберите действия",
+ "hint": "Правила применяются по порядку. Перетащите для изменения порядка.",
+ "test": "Проверить правила"
+ },
+ "service": {
+ "intro": "Синхронизация между устройствами с помощью RSS сервисов.",
+ "select": "Выберите сервис",
+ "suggest": "Предложить новый сервис",
+ "overwriteWarning": "Локальные источники будут удалены если они существуют в сервисе.",
+ "groupsWarning": "Группы не синхронизируются автоматически через сервис.",
+ "rateLimitWarning": "Чтобы избежать ограничения частоты запросов, Вам нужно создать свой ключ API.",
+ "removeAd": "Убрать рекламу",
+ "endpoint": "Endpoint",
+ "username": "Имя пользователя",
+ "password": "Пароль",
+ "unchanged": "Без изменений",
+ "fetchLimit": "Ограничение синхронизации",
+ "fetchLimitNum": "{count, plural, =1 {# последняя статья} other {# последних статей}}",
+ "importGroups": "Импортировать группы",
+ "failure": "Нет подключения к сервису",
+ "failureHint": "Please check the service configuration or network status.",
+ "fetchUnlimited": "Без ограничений (не рекомендуется)",
+ "exportToLite": "Экспорт в Fluent Reader Lite"
+ },
+ "app": {
+ "cleanup": "Очистка",
+ "cache": "Очистить кэш",
+ "cacheSize": "Закэшировано {size} данных",
+ "deleteChoices": "Удалить статьи старше … дней",
+ "confirmDelete": "Удалить",
+ "daysAgo": "{days, plural, =1 {# дня} other {# дней}} назад",
+ "deleteAll": "Удалить все статьи",
+ "calculatingSize": "Вычисление размера…",
+ "itemSize": "Статьями занято примерно {size} пространства локального хранилища",
+ "confirmImport": "Вы действительно хотите импортировать данные из файла резервной копии? Все текущие данные будут удалены.",
+ "data": "Данные приложения",
+ "backup": "Резервная копия",
+ "restore": "Восстановление",
+ "frData": "Данные Fluent Reader",
+ "language": "Язык интерфейса",
+ "theme": "Тема",
+ "lightTheme": "Светлая",
+ "darkTheme": "Тёмная",
+ "enableProxy": "Включить прокси",
+ "badUrl": "Недопустимый URL",
+ "pac": "PAC Адрес",
+ "setPac": "Установить PAC",
+ "pacHint": "Для Socks прокси рекомендуется, чтобы PAC возвращал \"SOCKS5\" для DNS на стороне прокси. Выключение прокси требует перезапуска.",
+ "fetchInterval": "Интервал автоматического обновления",
+ "never": "Никогда"
+ }
+}
From 699246a2c22227af13321bc92c804eb89ddba524 Mon Sep 17 00:00:00 2001
From: Bruce Liu
Date: Wed, 8 Jun 2022 11:37:20 -0700
Subject: [PATCH 5/7] fix dark theme fonts, update metadata
---
dist/article/article.css | 3 +--
dist/styles/global.css | 3 +--
electron-builder-mas.yml | 3 ++-
electron-builder.yml | 2 ++
package-lock.json | 2 +-
package.json | 2 +-
src/scripts/settings.ts | 31 +++++++++++++++++++++++--------
7 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/dist/article/article.css b/dist/article/article.css
index 4b94154..f69ccb9 100644
--- a/dist/article/article.css
+++ b/dist/article/article.css
@@ -3,8 +3,7 @@
html,
body {
margin: 0;
- font-family: "Segoe UI", "Source Han Sans Regular",
- sans-serif;
+ font-family: "Segoe UI", "Source Han Sans Regular", sans-serif;
}
body {
padding: 12px 96px 32px;
diff --git a/dist/styles/global.css b/dist/styles/global.css
index 93abd44..8b6e63f 100644
--- a/dist/styles/global.css
+++ b/dist/styles/global.css
@@ -49,8 +49,7 @@ body.darwin {
html,
body {
background-color: transparent;
- font-family: "Segoe UI", "Source Han Sans Regular",
- sans-serif;
+ font-family: "Segoe UI", "Source Han Sans Regular", sans-serif;
height: 100%;
overflow: hidden;
margin: 0;
diff --git a/electron-builder-mas.yml b/electron-builder-mas.yml
index f760f6b..6a2ee24 100644
--- a/electron-builder-mas.yml
+++ b/electron-builder-mas.yml
@@ -1,5 +1,5 @@
appId: DevHYLiu.FluentReader
-buildVersion: 25
+buildVersion: 26
productName: Fluent Reader
copyright: Copyright © 2020 Haoyuan Liu
files:
@@ -29,6 +29,7 @@ mac:
- it
- nl
- ko
+ - ru
minimumSystemVersion: 10.14.0
mas:
entitlements: build/entitlements.mas.plist
diff --git a/electron-builder.yml b/electron-builder.yml
index 047ed1d..dff5552 100644
--- a/electron-builder.yml
+++ b/electron-builder.yml
@@ -26,6 +26,7 @@ mac:
- it
- nl
- ko
+ - ru
win:
target:
- nsis
@@ -49,6 +50,7 @@ appx:
- it
- nl
- ko
+ - ru
showNameOnTiles: true
setBuildNumber: true
nsis:
diff --git a/package-lock.json b/package-lock.json
index 519a19a..5db86f6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "fluent-reader",
- "version": "1.1.0",
+ "version": "1.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/package.json b/package.json
index 3d889a2..07d710b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "fluent-reader",
- "version": "1.1.0",
+ "version": "1.1.1",
"description": "Modern desktop RSS reader",
"main": "./dist/electron.js",
"scripts": {
diff --git a/src/scripts/settings.ts b/src/scripts/settings.ts
index 3bf83d0..a7e7fa6 100644
--- a/src/scripts/settings.ts
+++ b/src/scripts/settings.ts
@@ -7,8 +7,7 @@ import { SourceTextDirection } from "./models/source"
let lightTheme: IPartialTheme = {
defaultFontStyle: {
- fontFamily:
- '"Segoe UI", "Source Han Sans Regular", sans-serif',
+ fontFamily: '"Segoe UI", "Source Han Sans Regular", sans-serif',
},
}
let darkTheme: IPartialTheme = {
@@ -42,13 +41,29 @@ let darkTheme: IPartialTheme = {
}
export function setThemeDefaultFont(locale: string) {
- switch(locale) {
- case "zh-CN": lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei", sans-serif'; break
- case "zh-TW": lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans TC Regular", "Microsoft JhengHei", sans-serif'; break
- case "ja": lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans JP Regular", "Yu Gothic UI", sans-serif'; break
- case "ko": lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans KR Regular", "Malgun Gothic", sans-serif'; break
- default: lightTheme.defaultFontStyle.fontFamily = '"Segoe UI", "Source Han Sans Regular", sans-serif'
+ switch (locale) {
+ case "zh-CN":
+ lightTheme.defaultFontStyle.fontFamily =
+ '"Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei", sans-serif'
+ break
+ case "zh-TW":
+ lightTheme.defaultFontStyle.fontFamily =
+ '"Segoe UI", "Source Han Sans TC Regular", "Microsoft JhengHei", sans-serif'
+ break
+ case "ja":
+ lightTheme.defaultFontStyle.fontFamily =
+ '"Segoe UI", "Source Han Sans JP Regular", "Yu Gothic UI", sans-serif'
+ break
+ case "ko":
+ lightTheme.defaultFontStyle.fontFamily =
+ '"Segoe UI", "Source Han Sans KR Regular", "Malgun Gothic", sans-serif'
+ break
+ default:
+ lightTheme.defaultFontStyle.fontFamily =
+ '"Segoe UI", "Source Han Sans Regular", sans-serif'
}
+ darkTheme.defaultFontStyle.fontFamily =
+ lightTheme.defaultFontStyle.fontFamily
applyThemeSettings()
}
export function setThemeSettings(theme: ThemeSettings) {
From 2bba8621aca80f8dd09b5fc10077ec88eb449b11 Mon Sep 17 00:00:00 2001
From: 0x1336 <91096964+0x1336@users.noreply.github.com>
Date: Wed, 8 Jun 2022 19:57:10 +0100
Subject: [PATCH 6/7] pt-PT Translation (#361)
* Added pt-PT
Added pt-PT (Portuguese from Portugal )
* Create pt-PT.json
Added pt-PT (Portuguese from Portugal) translation. Done it with pt-BR and en-US as basis.
* Update README.md
* Update README.md
* Update README.md
Co-authored-by: Haoyuan Liu
---
src/scripts/i18n/README.md | 1 +
src/scripts/i18n/_locales.ts | 2 +
src/scripts/i18n/pt-PT.json | 241 +++++++++++++++++++++++++++++++++++
3 files changed, 244 insertions(+)
create mode 100644 src/scripts/i18n/pt-PT.json
diff --git a/src/scripts/i18n/README.md b/src/scripts/i18n/README.md
index 18d0301..802dbb3 100644
--- a/src/scripts/i18n/README.md
+++ b/src/scripts/i18n/README.md
@@ -18,6 +18,7 @@ Currently, Fluent Reader supports the following languages.
| nl | Nederlands | [@Vistaus](https://github.com/Vistaus) |
| it | Italiano | [@andrewasd](https://github.com/andrewasd) |
| pt-BR | Português do Brasil | [@fabianski7](https://github.com/fabianski7) |
+| pt-PT | Português de Portugal | [@0x1336](https://github.com/0x1336) |
| ko | 한글 | [@1drive](https://github.com/1drive) |
| ru | Russian | [@nxblnd](https://github.com/nxblnd) |
diff --git a/src/scripts/i18n/_locales.ts b/src/scripts/i18n/_locales.ts
index 229b6a2..e8c64d0 100644
--- a/src/scripts/i18n/_locales.ts
+++ b/src/scripts/i18n/_locales.ts
@@ -14,6 +14,7 @@ import ru from "./ru.json"
import pt_BR from "./pt-BR.json"
import fi_FI from "./fi-FI.json"
import ko from "./ko.json"
+import pt_PT from "./pt-PT.json"
const locales = {
"en-US": en_US,
@@ -32,6 +33,7 @@ const locales = {
"pt-BR": pt_BR,
"fi-FI": fi_FI,
"ko": ko,
+ "pt-PT": pt_PT,
}
export default locales
diff --git a/src/scripts/i18n/pt-PT.json b/src/scripts/i18n/pt-PT.json
new file mode 100644
index 0000000..56354b2
--- /dev/null
+++ b/src/scripts/i18n/pt-PT.json
@@ -0,0 +1,241 @@
+{
+ "allArticles": "Todos os artigos",
+ "add": "Adicionar",
+ "create": "Criar",
+ "icon": "Ícone",
+ "name": "Nome",
+ "openExternal": "Abrir externamente",
+ "emptyName": "Este campo não pode ficar vazio.",
+ "emptyField": "Este campo não pode ficar vazio.",
+ "edit": "Editar",
+ "delete": "Eliminar",
+ "followSystem": "Seguir o sistema",
+ "more": "Mais",
+ "close": "Fechar",
+ "search": "Pesquisar",
+ "loadMore": "Carregar mais",
+ "dangerButton": "Confirmar {action}?",
+ "confirmMarkAll": "Deseja mesmo marcar todos os artigos desta página como lidos?",
+ "confirm": "Confirmar",
+ "cancel": "Cancelar",
+ "default": "Padrão",
+ "time": {
+ "now": "agora",
+ "m": "m",
+ "h": "h",
+ "d": "d",
+ "minute": "{m, plural, =1 {# minuto} other {# minutos}}",
+ "hour": "{h, plural, =1 {# hora} other {# horas}}",
+ "day": "{d, plural, =1 {# dia} other {# dias}}"
+ },
+ "log": {
+ "empty": "Nenhuma notificação",
+ "fetchFailure": "Falha ao carregar a fonte \"{name}\".",
+ "fetchSuccess": "{count, plural, =1 {# Artigo} other {# Artigos}} foram atualizados com sucesso.",
+ "networkError": "Ocorreu um erro na rede.",
+ "parseError": "Ocorreu um erro ao analisar o feed XML.",
+ "syncFailure": "Falha ao sincronizar com o serviço"
+ },
+ "nav": {
+ "menu": "Menu",
+ "refresh": "Atualizar",
+ "markAllRead": "Marcar todos como lidos",
+ "notifications": "Notificações",
+ "view": "Visualização",
+ "settings": "Definições",
+ "minimize": "Minimizar",
+ "maximize": "Maximizar"
+ },
+ "menu": {
+ "close": "Fechar menu",
+ "subscriptions": "Subscrições"
+ },
+ "article": {
+ "error": "Falha ao carregar o artigo.",
+ "reload": "Recarregar?",
+ "empty": "Nenhum artigo",
+ "untitled": "(Sem título)",
+ "hide": "Ocultar artigo",
+ "unhide": "Exibir artigo",
+ "markRead": "Marcar como lido",
+ "markUnread": "Marcar como não lido",
+ "markAbove": "Marcar artigo(s) acima como lido(s)",
+ "markBelow": "Marcar artigo(s) abaixo como não lido(s)",
+ "star": "Marcar como favorito",
+ "unstar": "Remover marcação",
+ "fontSize": "Tamanho da fonte",
+ "loadWebpage": "Carregar página web",
+ "loadFull": "Carregar todo o conteúdo",
+ "notify": "Notificar se atualizado em segundo plano",
+ "dontNotify": "Não notificar",
+ "textDir": "Direção do texto",
+ "LTR": "Esquerda-para-direita",
+ "RTL": "Direita-para-esquerda",
+ "Vertical": "Vertical",
+ "font": "Fonte"
+ },
+ "context": {
+ "share": "Partilhar",
+ "read": "Ler",
+ "copyTitle": "Copiar título",
+ "copyURL": "Copiar link",
+ "copy": "Copiar",
+ "search": "Pesquisar \"{text}\" no {engine}",
+ "view": "Visualizar",
+ "cardView": "Como cartões",
+ "listView": "Em lista",
+ "magazineView": "Como revista",
+ "compactView": "Compacto",
+ "filter": "Filtrar",
+ "unreadOnly": "Apenas não lidos",
+ "starredOnly": "Apenas favoritos",
+ "fullSearch": "Pesquisar em todo o texto",
+ "showHidden": "Exibir artigos ocultos",
+ "manageSources": "Gerir fontes",
+ "saveImageAs": "Guardar imagem como …",
+ "copyImage": "Copiar imagem",
+ "copyImageURL": "Copiar link da imagem",
+ "caseSensitive": "Diferenciar maiúsculas e minúsculas",
+ "showCover": "Mostrar capa",
+ "showSnippet": "Mostrar trecho",
+ "fadeRead": "Desaparecer artigos lidos"
+ },
+ "searchEngine": {
+ "name": "Motor de pesquisa",
+ "google": "Google",
+ "bing": "Bing",
+ "baidu": "Baidu",
+ "duckduckgo": "DuckDuckGo"
+ },
+ "settings": {
+ "writeError": "Ocorreu um erro ao gravar o ficheiro.",
+ "name": "Definições",
+ "fetching": "Atualizando fontes, aguarde por favor …",
+ "exit": "Sair das definições",
+ "sources": "Fontes",
+ "grouping": "Grupos",
+ "rules": "Regras",
+ "service": "Serviço",
+ "app": "Preferências",
+ "about": "Sobre",
+ "version": "Versão",
+ "shortcuts": "Atalhos",
+ "openSource": "Código aberto",
+ "feedback": "Feedback"
+ },
+ "sources": {
+ "serviceWarning": "Fontes importadas ou adicionadas aqui não serão sincronizadas com o seu serviço.",
+ "serviceManaged": "Esta fonte é gerenciada pelo seu serviço.",
+ "untitled": "Fonte",
+ "errorAdd": "Ocorreu um erro ao adicionar a fonte.",
+ "errorParse": "Ocorreu um erro ao analisar o arquivo OPML.",
+ "errorParseHint": "Certifique-se de que o arquivo não esteja corrompido e que esteja codificado com UTF-8.",
+ "errorImport": "Erro ao importar {count, plural, =1 {# fonte} other {# fontes}}.",
+ "exist": "Esta fonte já existe.",
+ "opmlFile": "Ficheiro OPML",
+ "name": "Nome da fonte",
+ "editName": "Editar nome",
+ "fetchFrequency": "Limite da frequência de atualização",
+ "unlimited": "Ilimitado",
+ "openTarget": "Método padrão de carregamento dos artigos",
+ "delete": "Eliminar fonte",
+ "add": "Adicionar fonte",
+ "import": "Importar",
+ "export": "Exportar",
+ "rssText": "Texto completo do RSS",
+ "loadWebpage": "Carregar página web",
+ "inputUrl": "Insira a URL",
+ "badIcon": "Ícone inválido",
+ "badUrl": "URL inválida",
+ "deleteWarning": "A fonte e todos os artigos guardados serão removidos.",
+ "selected": "Fonte selecionada",
+ "selectedMulti": "Múltiplas fontes selecionadas"
+ },
+ "groups": {
+ "exist": "Este grupo já existe.",
+ "type": "Tipo",
+ "group": "Grupo",
+ "source": "Fonte",
+ "capacity": "Capacidade",
+ "exitGroup": "Voltar para os grupos",
+ "deleteSource": "Eliminar do grupo",
+ "sourceHint": "Arraste e solte as fontes para reorganizá-las.",
+ "create": "Criar grupo",
+ "selectedGroup": "Grupo selecionado",
+ "selectedSource": "Fonte selecionada",
+ "enterName": "Insira o nome",
+ "editName": "Editar nome",
+ "deleteGroup": "Eliminar grupo",
+ "chooseGroup": "Selecione um grupo",
+ "addToGroup": "Adicionar a ...",
+ "groupHint": "Clique duplo no grupo para editar as fontes. Arraste e solte para reorganizá-los."
+ },
+ "rules": {
+ "intro": "Marcar artigos automaticamente ou enviar notificações com expressões regulares.",
+ "help": "Saber mais",
+ "source": "Fonte",
+ "selectSource": "Selecionar uma fonte",
+ "new": "Nova regra",
+ "if": "Se",
+ "then": "Então",
+ "title": "Título",
+ "content": "Conteúdo",
+ "fullSearch": "Título ou conteúdo",
+ "creator": "Autor",
+ "match": "corresponde",
+ "notMatch": "não corresponde",
+ "regex": "Expressão regular",
+ "badRegex": "Expressão regular inválida.",
+ "action": "Ações",
+ "selectAction": "Selecionar ações",
+ "hint": "As regras serão aplicadas em ordem. Arraste e solte para reorganizar.",
+ "test": "Testar regras"
+ },
+ "service": {
+ "intro": "Sincronização entre dispositivos com serviços RSS.",
+ "select": "Selecione um serviço",
+ "suggest": "Sugerir um novo serviço",
+ "overwriteWarning": "Fontes locais serão eliminadas se elas existirem no serviço.",
+ "groupsWarning": "Grupos não são automaticamente sincronizados com o serviço.",
+ "rateLimitWarning": "Para evitar limitações do serviço, você precisa criar sua própria chave de API.",
+ "removeAd": "Remover Anuncio",
+ "endpoint": "Endpoint",
+ "username": "Utilizador",
+ "password": "Password",
+ "unchanged": "Inalterado",
+ "fetchLimit": "Limite de sincronização",
+ "fetchLimitNum": "{count} últimos artigos",
+ "importGroups": "Importar grupos",
+ "failure": "Não foi possível conectar ao serviço",
+ "failureHint": "Por favor verifique a configuração do serviço ou o estado da rede.",
+ "fetchUnlimited": "Ilimitado (não recomendado)",
+ "exportToLite": "Exportar para o Fluent Reader Lite"
+ },
+ "app": {
+ "cleanup": "Limpar",
+ "cache": "Limpar cache",
+ "cacheSize": "{size} de dados em cache",
+ "deleteChoices": "Eliminar artigos de ... dias atrás",
+ "confirmDelete": "Eliminar",
+ "daysAgo": "{days, plural, =1 {# dia} other {# dias}} atrás",
+ "deleteAll": "Eliminar todos os artigos",
+ "calculatingSize": "Calculando tamanho...",
+ "itemSize": "Cerca de {size} do armazenamento local é ocupado por artigos",
+ "confirmImport": "Do you really want to import data from the backup file? All current data will be wiped.",
+ "data": "Dados da aplicação",
+ "backup": "Backup",
+ "restore": "Restorar",
+ "frData": "Dados do Fluent Reader",
+ "language": "Idioma",
+ "theme": "Tema",
+ "lightTheme": "Modo claro",
+ "darkTheme": "Modo escuro",
+ "enableProxy": "Ativar proxy",
+ "badUrl": "URL inválida",
+ "pac": "Endereço PAC",
+ "setPac": "Definir PAC",
+ "pacHint": "Para proxies Socks, é recomendado para o PAC retornar \"SOCKS5\" para o proxy-side DNS. Desligar o proxy requer um reinicio.",
+ "fetchInterval": "Intervalo de atualização automática",
+ "never": "Nunca"
+ }
+}
From efb704c597e344c3485497ce696e05b65a292e29 Mon Sep 17 00:00:00 2001
From: Bruce Liu
Date: Thu, 9 Jun 2022 14:14:33 -0700
Subject: [PATCH 7/7] fix article switch after loading full content
---
electron-builder-mas.yml | 2 ++
electron-builder.yml | 4 ++++
src/components/article.tsx | 22 ++++++++++++++--------
src/components/settings/app.tsx | 1 +
4 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/electron-builder-mas.yml b/electron-builder-mas.yml
index 6a2ee24..0390607 100644
--- a/electron-builder-mas.yml
+++ b/electron-builder-mas.yml
@@ -30,6 +30,8 @@ mac:
- nl
- ko
- ru
+ - pt_BR
+ - pt_PT
minimumSystemVersion: 10.14.0
mas:
entitlements: build/entitlements.mas.plist
diff --git a/electron-builder.yml b/electron-builder.yml
index dff5552..ee8e1a9 100644
--- a/electron-builder.yml
+++ b/electron-builder.yml
@@ -27,6 +27,8 @@ mac:
- nl
- ko
- ru
+ - pt_BR
+ - pt_PT
win:
target:
- nsis
@@ -51,6 +53,8 @@ appx:
- nl
- ko
- ru
+ - pt-BR
+ - pt-PT
showNameOnTiles: true
setBuildNumber: true
nsis:
diff --git a/src/components/article.tsx b/src/components/article.tsx
index 1543458..18a640a 100644
--- a/src/components/article.tsx
+++ b/src/components/article.tsx
@@ -328,17 +328,22 @@ class Article extends React.Component {
}
loadFull = async () => {
this.setState({ fullContent: "", loaded: false, error: false })
+ const link = this.props.item.link
try {
- const result = await fetch(this.props.item.link)
+ const result = await fetch(link)
if (!result || !result.ok) throw new Error()
const html = await decodeFetchResponse(result, true)
- this.setState({ fullContent: html })
+ if (link === this.props.item.link) {
+ this.setState({ fullContent: html })
+ }
} catch {
- this.setState({
- loaded: true,
- error: true,
- errorDescription: "MERCURY_PARSER_FAILURE",
- })
+ if (link === this.props.item.link) {
+ this.setState({
+ loaded: true,
+ error: true,
+ errorDescription: "MERCURY_PARSER_FAILURE",
+ })
+ }
}
}
@@ -467,7 +472,8 @@ class Article extends React.Component {
className={this.state.error ? "error" : ""}
key={
this.props.item._id +
- (this.state.loadWebpage ? "_" : "")
+ (this.state.loadWebpage ? "_" : "") +
+ (this.state.loadFull ? "__" : "")
}
src={
this.state.loadWebpage
diff --git a/src/components/settings/app.tsx b/src/components/settings/app.tsx
index 9ceec93..5afaf81 100644
--- a/src/components/settings/app.tsx
+++ b/src/components/settings/app.tsx
@@ -135,6 +135,7 @@ class AppTab extends React.Component {
{ key: "it", text: "Italiano" },
{ key: "nl", text: "Nederlands" },
{ key: "pt-BR", text: "Português do Brasil" },
+ { key: "pt-PT", text: "Português de Portugal" },
{ key: "fi-FI", text: "Suomi" },
{ key: "sv", text: "Svenska" },
{ key: "tr", text: "Türkçe" },