Merge pull request #425 from yang991178/1.1.1

Version 1.1.1
This commit is contained in:
Haoyuan Liu 2022-06-09 15:15:41 -07:00 committed by GitHub
commit d5ab8bf53f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 608 additions and 28 deletions

View File

@ -3,8 +3,7 @@
html,
body {
margin: 0;
font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei",
sans-serif;
font-family: "Segoe UI", "Source Han Sans Regular", sans-serif;
}
body {
padding: 12px 96px 32px;

View File

@ -49,12 +49,27 @@ body.darwin {
html,
body {
background-color: transparent;
font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei",
sans-serif;
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);

View File

@ -1,5 +1,5 @@
appId: DevHYLiu.FluentReader
buildVersion: 25
buildVersion: 26
productName: Fluent Reader
copyright: Copyright © 2020 Haoyuan Liu
files:
@ -29,6 +29,9 @@ mac:
- it
- nl
- ko
- ru
- pt_BR
- pt_PT
minimumSystemVersion: 10.14.0
mas:
entitlements: build/entitlements.mas.plist

View File

@ -26,6 +26,9 @@ mac:
- it
- nl
- ko
- ru
- pt_BR
- pt_PT
win:
target:
- nsis
@ -49,6 +52,9 @@ appx:
- it
- nl
- ko
- ru
- pt-BR
- pt-PT
showNameOnTiles: true
setBuildNumber: true
nsis:

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "fluent-reader",
"version": "1.1.0",
"version": "1.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {

View File

@ -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": {

View File

@ -328,17 +328,22 @@ class Article extends React.Component<ArticleProps, ArticleState> {
}
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<ArticleProps, ArticleState> {
className={this.state.error ? "error" : ""}
key={
this.props.item._id +
(this.state.loadWebpage ? "_" : "")
(this.state.loadWebpage ? "_" : "") +
(this.state.loadFull ? "__" : "")
}
src={
this.state.loadWebpage

View File

@ -23,10 +23,15 @@ const CompactCard: React.FunctionComponent<Card.Props> = props => (
text={props.item.title}
filter={props.filter}
title
dir={props.source.textDir}
/>
</span>
<span className="snippet">
<Highlights text={props.item.snippet} filter={props.filter} />
<Highlights
text={props.item.snippet}
filter={props.filter}
dir={props.source.textDir}
/>
</span>
</div>
<Time date={props.item.date} />

View File

@ -25,10 +25,19 @@ const DefaultCard: React.FunctionComponent<Card.Props> = props => (
) : null}
<CardInfo source={props.source} item={props.item} />
<h3 className="title">
<Highlights text={props.item.title} filter={props.filter} title />
<Highlights
text={props.item.title}
filter={props.filter}
title
dir={props.source.textDir}
/>
</h3>
<p className={"snippet" + (props.item.thumb ? "" : " show")}>
<Highlights text={props.item.snippet} filter={props.filter} />
<Highlights
text={props.item.snippet}
filter={props.filter}
dir={props.source.textDir}
/>
</p>
</div>
)

View File

@ -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<HighlightsProps> = props => {
@ -57,10 +59,22 @@ const Highlights: React.FunctionComponent<HighlightsProps> = props => {
}
}
const testStyle = {
direction: "inherit",
} as React.CSSProperties
if (props.dir === SourceTextDirection.RTL) {
testStyle.direction = "rtl"
}
return (
<>
{spans.map(([text, flag]) =>
flag ? <span className="h">{text}</span> : text
flag ? (
<div className="h" style={testStyle}>
{text}
</div>
) : (
<div style={testStyle}>{text}</div>
)
)}
</>
)

View File

@ -31,6 +31,7 @@ const ListCard: React.FunctionComponent<Card.Props> = props => (
text={props.item.title}
filter={props.filter}
title
dir={props.source.textDir}
/>
</h3>
{Boolean(props.viewConfigs & ViewConfigs.ShowSnippet) && (
@ -38,6 +39,7 @@ const ListCard: React.FunctionComponent<Card.Props> = props => (
<Highlights
text={props.item.snippet}
filter={props.filter}
dir={props.source.textDir}
/>
</p>
)}

View File

@ -28,12 +28,14 @@ const MagazineCard: React.FunctionComponent<Card.Props> = props => (
text={props.item.title}
filter={props.filter}
title
dir={props.source.textDir}
/>
</h3>
<p className="snippet">
<Highlights
text={props.item.snippet}
filter={props.filter}
dir={props.source.textDir}
/>
</p>
</div>

View File

@ -135,10 +135,12 @@ class AppTab extends React.Component<AppTabProps, AppTabState> {
{ 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" },
{ key: "uk", text: "Українська" },
{ key: "ru", text: "Русский" },
{ key: "ko", text: "한글" },
{ key: "ja", text: "日本語" },
{ key: "zh-CN", text: "中文(简体)" },

View File

@ -18,6 +18,8 @@ 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) |
Refer to the repo of [react-intl-universal](https://github.com/alibaba/react-intl-universal) to get started on internationalization.

View File

@ -10,9 +10,11 @@ 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"
import pt_PT from "./pt-PT.json"
const locales = {
"en-US": en_US,
@ -27,9 +29,11 @@ const locales = {
"tr": tr,
"it": it,
"uk": uk,
"ru": ru,
"pt-BR": pt_BR,
"fi-FI": fi_FI,
"ko": ko,
"pt-PT": pt_PT,
}
export default locales

241
src/scripts/i18n/pt-PT.json Normal file
View File

@ -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"
}
}

241
src/scripts/i18n/ru.json Normal file
View File

@ -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": "Никогда"
}
}

View File

@ -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<Promise<void>> {
return dispatch => {

View File

@ -5,13 +5,12 @@ 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',
fontFamily: '"Segoe UI", "Source Han Sans Regular", sans-serif',
},
}
const darkTheme: IPartialTheme = {
let darkTheme: IPartialTheme = {
...lightTheme,
palette: {
neutralLighterAlt: "#282828",
@ -41,6 +40,32 @@ 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'
}
darkTheme.defaultFontStyle.fontFamily =
lightTheme.defaultFontStyle.fontFamily
applyThemeSettings()
}
export function setThemeSettings(theme: ThemeSettings) {
window.settings.setThemeSettings(theme)
applyThemeSettings()