From e1069f6bd169d4bf41d6227bf2e6777d8515ccfb Mon Sep 17 00:00:00 2001 From: hoangnd Date: Thu, 25 Oct 2018 13:52:03 +0700 Subject: [PATCH 01/27] Translate dashboard to Vietnamese with i18n --- client/package-lock.json | 114 ++++++++++++++++-- client/package.json | 6 +- client/src/__locales/vi.js | 42 +++++++ .../components/Dashboard/BlockedDomains.js | 11 +- client/src/components/Dashboard/Clients.js | 11 +- client/src/components/Dashboard/Counters.js | 30 ++--- .../components/Dashboard/QueriedDomains.js | 11 +- client/src/components/Dashboard/Statistics.js | 9 +- client/src/components/Dashboard/index.js | 12 +- client/src/components/Header/Menu.js | 14 +-- client/src/components/Header/Version.js | 5 +- client/src/components/Header/index.js | 3 +- client/src/components/ui/Footer.js | 5 +- client/src/i18n.js | 25 ++++ client/src/index.js | 1 + 15 files changed, 240 insertions(+), 59 deletions(-) create mode 100644 client/src/__locales/vi.js create mode 100644 client/src/i18n.js diff --git a/client/package-lock.json b/client/package-lock.json index 1e9b0f5d..5b6b2e45 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -94,6 +94,21 @@ "integrity": "sha1-J87C30Cd9gr1gnDtj2qlVAnqhvY=", "dev": true }, + "@babel/runtime": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.1.2.tgz", + "integrity": "sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg==", + "requires": { + "regenerator-runtime": "^0.12.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, "@babel/template": { "version": "7.0.0-beta.44", "resolved": "http://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz", @@ -3111,6 +3126,15 @@ "sha.js": "^2.4.8" } }, + "create-react-context": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.3.tgz", + "integrity": "sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag==", + "requires": { + "fbjs": "^0.8.0", + "gud": "^1.0.0" + } + }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -5569,7 +5593,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -5590,12 +5615,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5610,17 +5637,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5737,7 +5767,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5749,6 +5780,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5763,6 +5795,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5770,12 +5803,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5794,6 +5829,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5874,7 +5910,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5886,6 +5923,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5971,7 +6009,8 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -6007,6 +6046,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6026,6 +6066,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6069,12 +6110,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -6230,6 +6273,11 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, "handle-thing": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", @@ -6543,6 +6591,14 @@ "uglify-js": "3.4.x" } }, + "html-parse-stringify2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz", + "integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=", + "requires": { + "void-elements": "^2.0.1" + } + }, "html-tags": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", @@ -6700,6 +6756,11 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, + "i18next": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-12.0.0.tgz", + "integrity": "sha512-Zy/nFpmBZxgmi6k9HkHbf+MwvAwiY5BDzNjNfvyLPKyalc2YBwwZtblESDlTKLDO8XSv23qYRY2uZcADDlRSjQ==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -12850,6 +12911,32 @@ "prop-types": "^15.6.0" } }, + "react-i18next": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-8.1.1.tgz", + "integrity": "sha512-o/33dyl5Wc8z/6QTsj6zU567oRK2pIDhlhNzelpTSmKrZuCsBPZZxEEOW6T+5MgDpCfr6RCsZbL1M2S+RH6i1w==", + "requires": { + "@babel/runtime": "^7.1.2", + "create-react-context": "0.2.3", + "hoist-non-react-statics": "3.0.1", + "html-parse-stringify2": "2.0.1" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.0.1.tgz", + "integrity": "sha512-1kXwPsOi0OGQIZNVMPvgWJ9tSnGMiMfJdihqEzrPEXlHOBh9AAHXX/QYmAJTXztnz/K+PQ8ryCb4eGaN6HlGbQ==", + "requires": { + "react-is": "^16.3.2" + } + } + } + }, + "react-is": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.0.tgz", + "integrity": "sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g==" + }, "react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", @@ -15604,6 +15691,11 @@ "indexof": "0.0.1" } }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + }, "walker": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", diff --git a/client/package.json b/client/package.json index 38e18a30..a85d00a4 100644 --- a/client/package.json +++ b/client/package.json @@ -6,7 +6,8 @@ "build-dev": "NODE_ENV=development ./node_modules/.bin/webpack --config webpack.dev.js", "watch": "NODE_ENV=development ./node_modules/.bin/webpack --config webpack.dev.js --watch", "build-prod": "NODE_ENV=production ./node_modules/.bin/webpack --config webpack.prod.js", - "lint": "eslint frontend/" + "lint": "eslint frontend/", + "start": "react-scripts start" }, "dependencies": { "@nivo/line": "^0.49.1", @@ -14,12 +15,15 @@ "classnames": "^2.2.6", "date-fns": "^1.29.0", "file-saver": "^1.3.8", + "i18next": "^12.0.0", + "i18next-browser-languagedetector": "^2.2.3", "lodash": "^4.17.10", "nanoid": "^1.2.3", "prop-types": "^15.6.1", "react": "^16.4.0", "react-click-outside": "^3.0.1", "react-dom": "^16.4.0", + "react-i18next": "^8.1.1", "react-modal": "^3.4.5", "react-redux": "^5.0.7", "react-redux-loading-bar": "^4.0.7", diff --git a/client/src/__locales/vi.js b/client/src/__locales/vi.js new file mode 100644 index 00000000..e2a03d14 --- /dev/null +++ b/client/src/__locales/vi.js @@ -0,0 +1,42 @@ +export default { + translation: { + // Header + Back: 'Quay lại', + Dashboard: 'Tổng quan', + Settings: 'Cài đặt', + Filters: 'Bộ lọc', + 'Query Log': 'Lịch sử truy vấn', + FAQ: 'Hỏi đáp', + version: 'phiên bản', + address: 'địa chỉ', + ON: 'Đang bật', + OFF: 'Đang tắt', + // Footer + Homepage: 'Trang chủ', + 'Report an issue': 'Báo lỗi', + // Dashboard + 'Enable protection': 'Bật bảo vệ', + 'Disable protection': 'Tắt bảo vệ', + 'Refresh statistics': 'Làm mới thống kê', + 'DNS Queries': 'Truy vấn DNS', + 'Blocked by': 'Chặn bởi', + 'Blocked malware/phishing': 'Mã độc/lừa đảo đã chặn', + 'Blocked adult websites': 'Website người lớn đã chặn', + 'Top queried domains': 'Tên miền truy vấn nhiều', + 'for the last 24 hours': 'trong 24 giờ qua', + 'No domains found': 'Không có tên miền nào', + 'Requests count': 'Số lần yêu cầu', + 'Top blocked domains': 'Tên miền chặn nhiều', + 'Top clients': 'Client dùng nhiều', + 'No clients found': 'Không có client nào', + 'General statistics': 'Thống kê chung', + 'A number of DNS quieries processed for the last 24 hours': 'Số yêu cầu DNS đã xử lý trong 24 giờ qua', + 'A number of DNS requests blocked by adblock filters and hosts blocklists': 'Số yêu cầu DNS bị chặn bởi bộ lọc quảng cáo và danh sách chặn host', + 'A number of DNS requests blocked by the AdGuard browsing security module': 'Số yêu cầu DNS bị chặn bởi chế độ bảo vệ duyệt web AdGuard', + 'A number of adult websites blocked': 'Số website người lớn đã chặn', + 'Enforced safe search': 'Tìm kiếm an toàn', + 'A number of DNS requests to search engines for which Safe Search was enforced': 'Số yêu cầu DNS tới công cụ tìm kiếm đã chuyển thành tìm kiếm an toàn', + 'Average processing time': 'Thời gian xử lý trung bình', + 'Average time in milliseconds on processing a DNS request': 'Thời gian trung bình cho một yêu cầu DNS tính bằng mili giây', + }, +}; diff --git a/client/src/components/Dashboard/BlockedDomains.js b/client/src/components/Dashboard/BlockedDomains.js index 707007a7..4ec291cd 100644 --- a/client/src/components/Dashboard/BlockedDomains.js +++ b/client/src/components/Dashboard/BlockedDomains.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import ReactTable from 'react-table'; import PropTypes from 'prop-types'; import map from 'lodash/map'; +import { withNamespaces, Trans } from 'react-i18next'; import Card from '../ui/Card'; import Cell from '../ui/Cell'; @@ -29,7 +30,7 @@ class BlockedDomains extends Component { ); }, }, { - Header: 'Requests count', + Header: Requests count, accessor: 'domain', maxWidth: 190, Cell: ({ value }) => { @@ -48,15 +49,16 @@ class BlockedDomains extends Component { }]; render() { + const { t } = this.props; return ( - + ( { ip: prop, domain: value } ))} columns={this.columns} showPagination={false} - noDataText="No domains found" + noDataText={ t('No domains found') } minRows={6} className="-striped -highlight card-table-overflow stats__table" /> @@ -71,6 +73,7 @@ BlockedDomains.propTypes = { replacedSafebrowsing: PropTypes.number.isRequired, replacedParental: PropTypes.number.isRequired, refreshButton: PropTypes.node.isRequired, + t: PropTypes.func, }; -export default BlockedDomains; +export default withNamespaces()(BlockedDomains); diff --git a/client/src/components/Dashboard/Clients.js b/client/src/components/Dashboard/Clients.js index 633ef08b..6a3596dd 100644 --- a/client/src/components/Dashboard/Clients.js +++ b/client/src/components/Dashboard/Clients.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import ReactTable from 'react-table'; import PropTypes from 'prop-types'; import map from 'lodash/map'; +import { Trans, withNamespaces } from 'react-i18next'; import Card from '../ui/Card'; import Cell from '../ui/Cell'; @@ -24,7 +25,7 @@ class Clients extends Component { accessor: 'ip', Cell: ({ value }) => (
{value}
), }, { - Header: 'Requests count', + Header: Requests count, accessor: 'count', Cell: ({ value }) => { const percent = getPercent(this.props.dnsQueries, value); @@ -37,15 +38,16 @@ class Clients extends Component { }]; render() { + const { t } = this.props; return ( - + ( { ip: prop, count: value } ))} columns={this.columns} showPagination={false} - noDataText="No clients found" + noDataText={ t('No clients found') } minRows={6} className="-striped -highlight card-table-overflow" /> @@ -58,6 +60,7 @@ Clients.propTypes = { topClients: PropTypes.object.isRequired, dnsQueries: PropTypes.number.isRequired, refreshButton: PropTypes.node.isRequired, + t: PropTypes.func, }; -export default Clients; +export default withNamespaces()(Clients); diff --git a/client/src/components/Dashboard/Counters.js b/client/src/components/Dashboard/Counters.js index a6260e10..7b4c6505 100644 --- a/client/src/components/Dashboard/Counters.js +++ b/client/src/components/Dashboard/Counters.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { Trans, withNamespaces } from 'react-i18next'; import Card from '../ui/Card'; import Tooltip from '../ui/Tooltip'; @@ -7,13 +8,13 @@ import Tooltip from '../ui/Tooltip'; const tooltipType = 'tooltip-custom--narrow'; const Counters = props => ( - +
- DNS Queries - + DNS Queries + @@ -23,8 +24,8 @@ const Counters = props => (
- Blocked by Filters - + Blocked by Filters + @@ -34,8 +35,8 @@ const Counters = props => (
- Blocked malware/phishing - + Blocked malware/phishing + @@ -45,8 +46,8 @@ const Counters = props => (
- Blocked adult websites - + Blocked adult websites + @@ -56,8 +57,8 @@ const Counters = props => (
- Enforced safe search - + Enforced safe search + @@ -67,8 +68,8 @@ const Counters = props => (
- Average processing time - + Average processing time + @@ -89,6 +90,7 @@ Counters.propTypes = { replacedSafesearch: PropTypes.number.isRequired, avgProcessingTime: PropTypes.number.isRequired, refreshButton: PropTypes.node.isRequired, + t: PropTypes.func, }; -export default Counters; +export default withNamespaces()(Counters); diff --git a/client/src/components/Dashboard/QueriedDomains.js b/client/src/components/Dashboard/QueriedDomains.js index 045ceb6c..fd30f0eb 100644 --- a/client/src/components/Dashboard/QueriedDomains.js +++ b/client/src/components/Dashboard/QueriedDomains.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import ReactTable from 'react-table'; import PropTypes from 'prop-types'; import map from 'lodash/map'; +import { withNamespaces, Trans } from 'react-i18next'; import Card from '../ui/Card'; import Cell from '../ui/Cell'; @@ -38,7 +39,7 @@ class QueriedDomains extends Component { ); }, }, { - Header: 'Requests count', + Header: Requests count, accessor: 'count', maxWidth: 190, Cell: ({ value }) => { @@ -52,15 +53,16 @@ class QueriedDomains extends Component { }]; render() { + const { t } = this.props; return ( - + ( { ip: prop, count: value } ))} columns={this.columns} showPagination={false} - noDataText="No domains found" + noDataText={ t('No domains found') } minRows={6} className="-striped -highlight card-table-overflow stats__table" /> @@ -73,6 +75,7 @@ QueriedDomains.propTypes = { topQueriedDomains: PropTypes.object.isRequired, dnsQueries: PropTypes.number.isRequired, refreshButton: PropTypes.node.isRequired, + t: PropTypes.func, }; -export default QueriedDomains; +export default withNamespaces()(QueriedDomains); diff --git a/client/src/components/Dashboard/Statistics.js b/client/src/components/Dashboard/Statistics.js index a54e0c00..3e7842b0 100644 --- a/client/src/components/Dashboard/Statistics.js +++ b/client/src/components/Dashboard/Statistics.js @@ -1,5 +1,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import { Trans } from 'react-i18next'; import Card from '../ui/Card'; import Line from '../ui/Line'; @@ -30,7 +31,7 @@ class Statistics extends Component { {dnsQueries}
- DNS Queries + DNS Queries
@@ -48,7 +49,7 @@ class Statistics extends Component { {getPercent(dnsQueries, blockedFiltering)}
- Blocked by Filters + Blocked by Filters
@@ -66,7 +67,7 @@ class Statistics extends Component { {getPercent(dnsQueries, replacedSafebrowsing)}
- Blocked malware/phishing + Blocked malware/phishing
@@ -84,7 +85,7 @@ class Statistics extends Component { {getPercent(dnsQueries, replacedParental)}
- Blocked adult websites + Blocked adult websites
diff --git a/client/src/components/Dashboard/index.js b/client/src/components/Dashboard/index.js index bf49b2a4..c8d43a2a 100644 --- a/client/src/components/Dashboard/index.js +++ b/client/src/components/Dashboard/index.js @@ -1,6 +1,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import 'whatwg-fetch'; +import { Trans, withNamespaces } from 'react-i18next'; import Statistics from './Statistics'; import Counters from './Counters'; @@ -30,25 +31,25 @@ class Dashboard extends Component { return ( ); } render() { - const { dashboard } = this.props; + const { dashboard, t } = this.props; const dashboardProcessing = dashboard.processing || dashboard.processingStats || dashboard.processingStatsHistory || dashboard.processingTopStats; - const refreshFullButton = ; + const refreshFullButton = ; const refreshButton =
diff --git a/client/src/i18n.js b/client/src/i18n.js new file mode 100644 index 00000000..cf5bfb71 --- /dev/null +++ b/client/src/i18n.js @@ -0,0 +1,25 @@ + +import i18n from 'i18next'; +import { reactI18nextModule } from 'react-i18next'; +import langDetect from 'i18next-browser-languagedetector'; +import viResource from './__locales/vi'; + +i18n + .use(langDetect) + .use(reactI18nextModule) // passes i18n down to react-i18next + .init({ + resources: { + vi: viResource, + }, + fallbackLng: 'en', + keySeparator: false, // we use content as keys + interpolation: { + escapeValue: false, // not needed for react!! + formatSeparator: ',', + }, + react: { + wait: true, + }, + }); + +export default i18n; diff --git a/client/src/index.js b/client/src/index.js index 16465633..1e95a210 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -5,6 +5,7 @@ import './components/App/index.css'; import App from './containers/App'; import configureStore from './configureStore'; import reducers from './reducers'; +import './i18n'; const store = configureStore(reducers, {}); // set initial state ReactDOM.render( From 3854a7acf9890813af409131ac94aa7317e1791e Mon Sep 17 00:00:00 2001 From: hoangnd Date: Thu, 25 Oct 2018 17:33:44 +0700 Subject: [PATCH 02/27] Add translate Setting page --- client/src/__locales/vi.js | 16 +++++++++++ client/src/components/Settings/Upstream.js | 15 ++++++---- client/src/components/Settings/index.js | 32 ++++++++++++---------- client/src/i18n.js | 2 +- 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/client/src/__locales/vi.js b/client/src/__locales/vi.js index e2a03d14..196ccab6 100644 --- a/client/src/__locales/vi.js +++ b/client/src/__locales/vi.js @@ -38,5 +38,21 @@ export default { 'A number of DNS requests to search engines for which Safe Search was enforced': 'Số yêu cầu DNS tới công cụ tìm kiếm đã chuyển thành tìm kiếm an toàn', 'Average processing time': 'Thời gian xử lý trung bình', 'Average time in milliseconds on processing a DNS request': 'Thời gian trung bình cho một yêu cầu DNS tính bằng mili giây', + // Setting + 'Block domains using filters and hosts files': 'Chặn tên miền sử dụng các bộ lọc và file hosts', + 'You can setup blocking rules in the Filters settings.': 'Bạn có thể thiết lập quy tắc chặn tại cài đặt Bộ lọc.', + 'Use AdGuard browsing security web service': 'Sử dụng dịch vụ bảo vệ duyệt web AdGuard', + 'AdGuard Home will check if domain is blacklisted by the browsing security web service. It will use privacy-friendly lookup API to perform the check: only a short prefix of the domain name SHA256 hash is sent to the server.': 'AdGuard Home sẽ kiểm tra tên miền với dịch vụ bảo vệ duyệt web. Tính năng sử dụng một API thân thiện với quyền riêng tư: chỉ một phần ngắn tiền tố mã băm SHA256 được gửi đến máy chủ', + 'Use AdGuard parental control web service': 'Sử dụng dịch vụ quản lý của phụ huynh AdGuard', + 'AdGuard Home will check if domain contains adult materials. It uses the same privacy-friendly API as the browsing security web service.': 'AdGuard Home sẽ kiểm tra nếu tên miền chứa từ khoá người lớn. Tính năng sử dụng API thân thiện với quyền riêng tư tương tự với dịch vụ bảo vệ duyệt web', + 'Enforce safe search': 'Bắt buộc tìm kiếm an toàn', + 'AdGuard Home can enforce safe search in the following search engines: Google, Bing, Yandex.': 'AdGuard Home có thể bắt buộc tìm kiếm an toàn với các dịch vụ tìm kiếm: Google, Bing, Yandex.', + 'No servers specified': 'Không có máy chủ nào được liệt kê', + 'No settings': 'Không có cài đặt nào', + 'General settings': 'Cài đặt chung', + 'Upstream DNS servers': 'Máy chủ DNS tìm kiếm', + 'If you keep this field empty, AdGuard Home will use Cloudflare DNS as an upstream. Use tls:// prefix for DNS over TLS servers.': 'Nếu bạn để trống mục này, AdGuard Home sẽ sử dụng Cloudflare DNS để tìm kiếm. Sử dụng tiền tố tls:// cho các máy chủ DNS dựa trên TLS.', + 'Test upstreams': 'Kiểm tra', + Apply: 'Áp dụng', }, }; diff --git a/client/src/components/Settings/Upstream.js b/client/src/components/Settings/Upstream.js index cbcc421d..276a201f 100644 --- a/client/src/components/Settings/Upstream.js +++ b/client/src/components/Settings/Upstream.js @@ -1,9 +1,10 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; +import { Trans, withNamespaces } from 'react-i18next'; import Card from '../ui/Card'; -export default class Upstream extends Component { +class Upstream extends Component { handleChange = (e) => { const { value } = e.currentTarget; this.props.handleUpstreamChange(value); @@ -23,11 +24,12 @@ export default class Upstream extends Component { 'btn btn-primary btn-standart mr-2': true, 'btn btn-primary btn-standart mr-2 btn-loading': this.props.processingTestUpstream, }); + const { t } = this.props; return ( Cloudflare DNS as an upstream. Use tls:// prefix for DNS over TLS servers.') } bodyType="card-body box-body--settings" >
@@ -44,14 +46,14 @@ export default class Upstream extends Component { type="button" onClick={this.handleTest} > - Test upstreams + Test upstreams
@@ -68,4 +70,7 @@ Upstream.propTypes = { handleUpstreamChange: PropTypes.func, handleUpstreamSubmit: PropTypes.func, handleUpstreamTest: PropTypes.func, + t: PropTypes.func, }; + +export default withNamespaces()(Upstream); diff --git a/client/src/components/Settings/index.js b/client/src/components/Settings/index.js index aa654cc2..fd0588b1 100644 --- a/client/src/components/Settings/index.js +++ b/client/src/components/Settings/index.js @@ -1,5 +1,6 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; +import { withNamespaces, Trans } from 'react-i18next'; import Upstream from './Upstream'; import Checkbox from '../ui/Checkbox'; import Loading from '../ui/Loading'; @@ -7,27 +8,27 @@ import PageTitle from '../ui/PageTitle'; import Card from '../ui/Card'; import './Settings.css'; -export default class Settings extends Component { +class Settings extends Component { settings = { filtering: { enabled: false, - title: 'Block domains using filters and hosts files', - subtitle: 'You can setup blocking rules in the Filters settings.', + title: this.props.t('Block domains using filters and hosts files'), + subtitle: this.props.t('You can setup blocking rules in the Filters settings.'), }, safebrowsing: { enabled: false, - title: 'Use AdGuard browsing security web service', - subtitle: 'AdGuard Home will check if domain is blacklisted by the browsing security web service. It will use privacy-friendly lookup API to perform the check: only a short prefix of the domain name SHA256 hash is sent to the server.', + title: this.props.t('Use AdGuard browsing security web service'), + subtitle: this.props.t('AdGuard Home will check if domain is blacklisted by the browsing security web service. It will use privacy-friendly lookup API to perform the check: only a short prefix of the domain name SHA256 hash is sent to the server.'), }, parental: { enabled: false, - title: 'Use AdGuard parental control web service', - subtitle: 'AdGuard Home will check if domain contains adult materials. It uses the same privacy-friendly API as the browsing security web service.', + title: this.props.t('Use AdGuard parental control web service'), + subtitle: this.props.t('AdGuard Home will check if domain contains adult materials. It uses the same privacy-friendly API as the browsing security web service.'), }, safesearch: { enabled: false, - title: 'Enforce safe search', - subtitle: 'AdGuard Home can enforce safe search in the following search engines: Google, Bing, Yandex.', + title: this.props.t('Enforce safe search'), + subtitle: this.props.t('AdGuard Home can enforce safe search in the following search engines: Google, Bing, Yandex.'), }, }; @@ -47,7 +48,7 @@ export default class Settings extends Component { if (this.props.dashboard.upstreamDns.length > 0) { this.props.testUpstream(this.props.dashboard.upstreamDns); } else { - this.props.addErrorToast({ error: 'No servers specified' }); + this.props.addErrorToast({ error: this.props.t('No servers specified') }); } }; @@ -64,22 +65,22 @@ export default class Settings extends Component { }); } return ( -
No settings
+
No settings
); } render() { - const { settings } = this.props; + const { settings, t } = this.props; const { upstreamDns } = this.props.dashboard; return ( - + {settings.processing && } {!settings.processing &&
- +
{this.renderSettings(settings.settingsList)}
@@ -108,4 +109,7 @@ Settings.propTypes = { handleUpstreamChange: PropTypes.func, setUpstream: PropTypes.func, upstream: PropTypes.string, + t: PropTypes.func, }; + +export default withNamespaces()(Settings); diff --git a/client/src/i18n.js b/client/src/i18n.js index cf5bfb71..e6737a4a 100644 --- a/client/src/i18n.js +++ b/client/src/i18n.js @@ -15,10 +15,10 @@ i18n keySeparator: false, // we use content as keys interpolation: { escapeValue: false, // not needed for react!! - formatSeparator: ',', }, react: { wait: true, + nsMode: 'fallback', }, }); From bfb7a252ad4458d3480f48417ca4e40c6da32fbf Mon Sep 17 00:00:00 2001 From: hoangrio Date: Thu, 25 Oct 2018 23:02:04 +0700 Subject: [PATCH 03/27] Fix i18n config for use : character --- client/package-lock.json | 46 ++++++++++++++-------------------------- client/src/i18n.js | 2 +- 2 files changed, 17 insertions(+), 31 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 5b6b2e45..41a69b71 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -5593,8 +5593,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5615,14 +5614,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5637,20 +5634,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5767,8 +5761,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5780,7 +5773,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5795,7 +5787,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5803,14 +5794,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5829,7 +5818,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5910,8 +5898,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5923,7 +5910,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6009,8 +5995,7 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -6046,7 +6031,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6066,7 +6050,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6110,14 +6093,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -6761,6 +6742,11 @@ "resolved": "https://registry.npmjs.org/i18next/-/i18next-12.0.0.tgz", "integrity": "sha512-Zy/nFpmBZxgmi6k9HkHbf+MwvAwiY5BDzNjNfvyLPKyalc2YBwwZtblESDlTKLDO8XSv23qYRY2uZcADDlRSjQ==" }, + "i18next-browser-languagedetector": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-2.2.3.tgz", + "integrity": "sha512-sJZ2n9Vgax0vGer23hJMwyO3FRO7P0dq2DXZPXWE329g3snfJUcw+S24Mp3lqJaxL/0McDu4BD75ds6pzIfhhw==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/client/src/i18n.js b/client/src/i18n.js index e6737a4a..7d5a5564 100644 --- a/client/src/i18n.js +++ b/client/src/i18n.js @@ -13,12 +13,12 @@ i18n }, fallbackLng: 'en', keySeparator: false, // we use content as keys + nsSeparator: false, // Fix character in content interpolation: { escapeValue: false, // not needed for react!! }, react: { wait: true, - nsMode: 'fallback', }, }); From 4590564fea78b4aa247db0e2bd0ac400c60c8252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20Rio?= Date: Fri, 26 Oct 2018 09:44:23 +0700 Subject: [PATCH 04/27] Complete translate client to Vietnamese --- client/src/__locales/vi.js | 60 +++++++++++++++++++++- client/src/components/Filters/UserRules.js | 28 +++++----- client/src/components/Filters/index.js | 35 +++++++------ client/src/components/Logs/index.js | 44 ++++++++++------ client/src/components/Toasts/Toast.js | 3 +- client/src/components/ui/Modal.js | 16 +++--- 6 files changed, 132 insertions(+), 54 deletions(-) diff --git a/client/src/__locales/vi.js b/client/src/__locales/vi.js index 196ccab6..23643ca1 100644 --- a/client/src/__locales/vi.js +++ b/client/src/__locales/vi.js @@ -38,7 +38,7 @@ export default { 'A number of DNS requests to search engines for which Safe Search was enforced': 'Số yêu cầu DNS tới công cụ tìm kiếm đã chuyển thành tìm kiếm an toàn', 'Average processing time': 'Thời gian xử lý trung bình', 'Average time in milliseconds on processing a DNS request': 'Thời gian trung bình cho một yêu cầu DNS tính bằng mili giây', - // Setting + // Settings 'Block domains using filters and hosts files': 'Chặn tên miền sử dụng các bộ lọc và file hosts', 'You can setup blocking rules in the Filters settings.': 'Bạn có thể thiết lập quy tắc chặn tại cài đặt Bộ lọc.', 'Use AdGuard browsing security web service': 'Sử dụng dịch vụ bảo vệ duyệt web AdGuard', @@ -54,5 +54,63 @@ export default { 'If you keep this field empty, AdGuard Home will use Cloudflare DNS as an upstream. Use tls:// prefix for DNS over TLS servers.': 'Nếu bạn để trống mục này, AdGuard Home sẽ sử dụng Cloudflare DNS để tìm kiếm. Sử dụng tiền tố tls:// cho các máy chủ DNS dựa trên TLS.', 'Test upstreams': 'Kiểm tra', Apply: 'Áp dụng', + // Settings Toasts + 'Disabled filtering': 'Đã tắt chặn quảng cáo', + 'Enabled filtering': 'Đã bật chặn quảng cáo', + 'Disabled safebrowsing': 'Đã tắt bảo vệ duyệt web', + 'Enabled safebrowsing': 'Đã bật bảo vệ duyệt web', + 'Disabled parental control': 'Đã tắt quản lý của phụ huynh', + 'Enabled parental control': 'Đã bật quản lý của phụ huynh', + 'Disabled safe search': 'Đã tắt tìm kiếm an toàn', + 'Enabled safe search': 'Đã bật tìm kiếm an toàn', + // Filters + Enabled: 'Kích hoạt', + Name: 'Tên', + 'Filter URL': 'URL bộ lọc', + 'Rules count': 'Số quy tắc', + 'Last time updated': 'Cập nhật cuối', + Actions: 'Thao tác', + Delete: 'Xoá', + 'Filters and hosts blocklists': 'Danh sách bộ lọc và hosts', + 'AdGuard Home understands basic adblock rules and hosts files syntax.': 'AdGuard home hiểu các quy tắc chặn quảng cáo đơn giản và cú pháp file hosts', + 'No filters added': 'Không có bộ lọc nào được thêm', + 'Add filter': 'Thêm bộ lọc', + Cancel: 'Huỷ', + 'Enter name': 'Nhập tên', + 'Enter URL': 'Nhập URL', + 'Check updates': 'Kiểm tra cập nhật', + 'New filter subscription': 'Đăng ký bộ lọc mới', + 'Enter a valid URL to a filter subscription or a hosts file.': 'Nhập URL hợp lệ của bộ lọc hoặc file hosts', + 'Custom filtering rules': 'Quy tắc lọc tuỳ chỉnh', + 'Enter one rule on a line. You can use either adblock rules or hosts files syntax.': 'Nhập mỗi quy tắc 1 dòng. Có thể sử dụng quy tắc chặn quảng cáo hoặc cú pháp file host', + Examples: 'Ví dụ', + 'block access to the example.org domain and all its subdomains': 'Chặn truy cập tới tên miền example.org và tất cả tên miền con', + 'unblock access to the example.org domain and all its subdomains': 'Không chặn truy cập tới tên miền example.org và tất cả tên miền con', + 'AdGuard Home will now return 127.0.0.1 address for the example.org domain (but not its subdomains).': 'AdGuard Home sẽ phản hồi địa chỉ IP 127.0.0.1 cho tên miền example.org (không áp dụng tên miền con)', + '! Here goes a comment': '! Đây là một chú thích', + 'just a comment': 'Chỉ là một chú thích', + '# Also a comment': '# Cũng là một chú thích', + // Logs + Unblock: 'Bỏ chặn', + Block: 'Chặn', + Time: 'Thời gian', + 'Domain name': 'Tên miền', + Type: 'Loại', + Response: 'Phản hồi', + Empty: 'Rỗng', + 'Show all': 'Hiện tất cả', + 'Show filtered': 'Chỉ hiện đã chặn', + 'No logs found': 'Không có lịch sử truy vấn', + 'Disable log': 'Tắt lịch sử truy vấn', + 'Download log file': 'Tải tập tin lịch sử truy vấn', + Refresh: 'Làm mới', + 'Enable log': 'Bật lịch sử truy vấn', + 'Last 5000 DNS queries': '5000 truy vấn DNS gần nhất', + Previous: 'Trang trước', + Next: 'Trang sau', + 'Loading...': 'Đang tải...', + Page: 'Trang', + of: 'của', + rows: 'hàng', }, }; diff --git a/client/src/components/Filters/UserRules.js b/client/src/components/Filters/UserRules.js index 4bd71a8f..1f47cf9a 100644 --- a/client/src/components/Filters/UserRules.js +++ b/client/src/components/Filters/UserRules.js @@ -1,8 +1,9 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import { Trans, withNamespaces } from 'react-i18next'; import Card from '../ui/Card'; -export default class UserRules extends Component { +class UserRules extends Component { handleChange = (e) => { const { value } = e.currentTarget; this.props.handleRulesChange(value); @@ -14,10 +15,11 @@ export default class UserRules extends Component { }; render() { + const { t } = this.props; return (