Add oneskyapp scripts for download and upload translations

This commit is contained in:
Ildar Kamalov 2018-11-16 12:45:41 +03:00
parent 25f469efd7
commit 5bf38041c5
13 changed files with 512 additions and 288 deletions

2
.gitignore vendored
View File

@ -12,6 +12,8 @@ debug
/dnsfilter.txt
/querylog.json
/querylog.json.1
/client/src/helpers/translations/node_modules
/client/src/helpers/translations/oneskyapp.json
# Test output
dnsfilter/dnsfilter.TestLotsOfRules*.pprof

18
client/package-lock.json generated vendored
View File

@ -95,9 +95,9 @@
"dev": true
},
"@babel/runtime": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.1.2.tgz",
"integrity": "sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg==",
"version": "7.1.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.1.5.tgz",
"integrity": "sha512-xKnPpXG/pvK1B90JkwwxSGii90rQGKtzcMt2gI5G6+M0REXaq6rOHsGC2ay6/d0Uje7zzvSzjEzfR3ENhFlrfA==",
"requires": {
"regenerator-runtime": "^0.12.0"
},
@ -12898,9 +12898,9 @@
}
},
"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==",
"version": "8.3.8",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-8.3.8.tgz",
"integrity": "sha512-ZcSpakSBcDxPJkl34fv/SI0TaoTDvVDrk4WpDF+WElorine+dHUjGMAA6RG5Km2KcLNW1t4GLunHprgKiqDrSw==",
"requires": {
"@babel/runtime": "^7.1.2",
"create-react-context": "0.2.3",
@ -12919,9 +12919,9 @@
}
},
"react-is": {
"version": "16.6.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.0.tgz",
"integrity": "sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g=="
"version": "16.6.3",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.3.tgz",
"integrity": "sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA=="
},
"react-lifecycles-compat": {
"version": "3.0.4",

View File

@ -1,135 +0,0 @@
export default {
translation: {
// Header
back: 'Back',
dashboard: 'Dashboard',
settings: 'Settings',
filters: 'Filters',
query_log: 'Query Log',
faq: 'FAQ',
version: 'version',
address: 'address',
on: 'ON',
off: 'OFF',
// Footer
copyright: 'Copyright',
homepage: 'Homepage',
report_an_issue: 'Report an issue',
// Dashboard
enable_protection: 'Enable protection',
enabled_protection: 'Enableed protection',
disable_protection: 'Disable protection',
disabled_protection: 'Disabled protection',
refresh_statics: 'Refresh statistics',
dns_query: 'DNS Queries',
blocked_by: 'Blocked by',
stats_malware_phishing: 'Blocked malware/phishing',
stats_adult: 'Blocked adult websites',
stats_query_domain: 'Top queried domains',
for_last_24_hours: 'for the last 24 hours',
no_domains_found: 'No domains found',
requests_count: 'Requests count',
top_blocked_domains: 'Top blocked domains',
top_clients: 'Top clients',
no_clients_found: 'No clients found',
general_statistics: 'General statistics',
number_of_dns_query_24_hours: 'A number of DNS quieries processed for the last 24 hours',
number_of_dns_query_blocked_24_hours: 'A number of DNS requests blocked by adblock filters and hosts blocklists',
number_of_dns_query_blocked_24_hours_by_sec: 'A number of DNS requests blocked by the AdGuard browsing security module',
number_of_dns_query_blocked_24_hours_adult: 'A number of adult websites blocked',
enforced_save_search: 'Enforced safe search',
number_of_dns_query_to_safe_search: 'A number of DNS requests to search engines for which Safe Search was enforced',
average_processing_time: 'Average processing time',
average_processing_time_hint: 'Average time in milliseconds on processing a DNS request',
// Settings
block_domain_use_filters_and_hosts: 'Block domains using filters and hosts files',
filters_block_toggle_hint: 'You can setup blocking rules in the <a href="#filters">Filters</a> settings.',
use_adguard_browsing_sec: 'Use AdGuard browsing security web service',
use_adguard_browsing_sec_hint: '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.',
use_adguard_parental: 'Use AdGuard parental control web service',
use_adguard_parental_hint: 'AdGuard Home will check if domain contains adult materials. It uses the same privacy-friendly API as the browsing security web service.',
enforce_safe_search: 'Enforce safe search',
enforce_save_search_hint: 'AdGuard Home can enforce safe search in the following search engines: Google, Youtube, Bing, and Yandex.',
no_servers_specified: 'No servers specified',
no_settings: 'No settings',
general_settings: 'General settings',
upstream_dns: 'Upstream DNS servers',
upstream_dns_hint: 'If you keep this field empty, AdGuard Home will use <a href="https://1.1.1.1/" target="_blank">Cloudflare DNS</a> as an upstream. Use tls:// prefix for DNS over TLS servers.',
test_upstream_btn: 'Test upstreams',
apply_btn: 'Apply',
// Settings Toasts
disabled_filtering_toast: 'Disabled filtering',
enabled_filtering_toast: 'Enabled filtering',
disabled_safe_browsing_toast: 'Disabled safebrowsing',
enabled_safe_browsing_toast: 'Enabled safebrowsing',
disabled_parental_toast: 'Disabled parental control',
enabled_parental_toast: 'Enabled parental control',
disabled_safe_search_toast: 'Disabled safe search',
enabled_save_search_toast: 'Enabled safe search',
// Filters
enabled_table_header: 'Enabled',
name_table_header: 'Name',
filter_url_table_header: 'Filter URL',
rules_count_table_header: 'Rules count',
last_time_updated_table_header: 'Last time updated',
actions_table_header: 'Actions',
delete_table_action: 'Delete',
filters_and_hosts: 'Filters and hosts blocklists',
filters_and_hosts_hint: 'AdGuard Home understands basic adblock rules and hosts files syntax.',
no_filters_added: 'No filters added',
add_filter_btn: 'Add filter',
cancel_btn: 'Cancel',
enter_name_hint: 'Enter name',
enter_url_hint: 'Enter URL',
check_updates_btn: 'Check updates',
new_filter_btn: 'New filter subscription',
enter_valid_filter_url: 'Enter a valid URL to a filter subscription or a hosts file.',
custom_filter_rules: 'Custom filtering rules',
custom_filter_rules_hint: 'Enter one rule on a line. You can use either adblock rules or hosts files syntax.',
examples_title: 'Examples',
example_meaning_filter_block: 'block access to the example.org domain and all its subdomains',
example_meaning_filter_whitelist: 'unblock access to the example.org domain and all its subdomains',
example_meaning_host_block: 'AdGuard Home will now return 127.0.0.1 address for the example.org domain (but not its subdomains).',
example_comment: '! Here goes a comment',
example_comment_meaning: 'just a comment',
example_comment_hash: '# Also a comment',
all_filters_up_to_date_toast: 'All filters are already up-to-date',
updated_upstream_dns_toast: 'Updated the upstream DNS servers',
dns_test_ok_toast: 'Specified DNS servers are working correctly',
dns_test_not_ok_toast: 'Server "{{key}}": could not be used, please check that you\'ve written it correctly',
// Logs
unblock_btn: 'Unblock',
block_btn: 'Block',
time_table_header: 'Time',
domain_name_table_header: 'Domain name',
type_table_header: 'Type',
response_table_header: 'Response',
empty_response_status: 'Empty',
show_all_filter_type: 'Show all',
show_filtered_type: 'Show filtered',
no_logs_found: 'No logs found',
disabled_log_btn: 'Disable log',
download_log_file_btn: 'Download log file',
refresh_btn: 'Refresh',
enabled_log_btn: 'Enable log',
last_5000_dns_queries: 'Last 5000 DNS queries',
previous_btn: 'Previous',
next_btn: 'Next',
loading_table_status: 'Loading...',
page_table_footer_text: 'Page',
of_table_footer_text: 'of',
rows_table_footer_text: 'rows',
updated_custom_filtering_toast: 'Updated the custom filtering rules',
rule_removed_from_custom_filtering_toast: 'Rule removed from the custom filtering rules',
rule_added_to_custom_filtering_toast: 'Rule added to the custom filtering rules',
query_log_disabled_toast: 'Query log disabled',
query_log_enabled_toast: 'Query log enabled',
// Popover
source_label: 'Source',
found_in_known_domain_db: 'Found in the known domains database.',
category_label: 'Category',
// Popover filter
rule_label: 'Rule',
filter_label: 'Filter',
},
};

View File

@ -0,0 +1,124 @@
{
"back": "Back",
"dashboard": "Dashboard",
"settings": "Settings",
"filters": "Filters",
"query_log": "Query Log",
"faq": "FAQ",
"version": "version",
"address": "address",
"on": "ON",
"off": "OFF",
"copyright": "Copyright",
"homepage": "Homepage",
"report_an_issue": "Report an issue",
"enable_protection": "Enable protection",
"enabled_protection": "Enabled protection",
"disable_protection": "Disable protection",
"disabled_protection": "Disabled protection",
"refresh_statics": "Refresh statistics",
"dns_query": "DNS Queries",
"blocked_by": "Blocked by",
"stats_malware_phishing": "Blocked malware\/phishing",
"stats_adult": "Blocked adult websites",
"stats_query_domain": "Top queried domains",
"for_last_24_hours": "for the last 24 hours",
"no_domains_found": "No domains found",
"requests_count": "Requests count",
"top_blocked_domains": "Top blocked domains",
"top_clients": "Top clients",
"no_clients_found": "No clients found",
"general_statistics": "General statistics",
"number_of_dns_query_24_hours": "A number of DNS quieries processed for the last 24 hours",
"number_of_dns_query_blocked_24_hours": "A number of DNS requests blocked by adblock filters and hosts blocklists",
"number_of_dns_query_blocked_24_hours_by_sec": "A number of DNS requests blocked by the AdGuard browsing security module",
"number_of_dns_query_blocked_24_hours_adult": "A number of adult websites blocked",
"enforced_save_search": "Enforced safe search",
"number_of_dns_query_to_safe_search": "A number of DNS requests to search engines for which Safe Search was enforced",
"average_processing_time": "Average processing time",
"average_processing_time_hint": "Average time in milliseconds on processing a DNS request",
"block_domain_use_filters_and_hosts": "Block domains using filters and hosts files",
"filters_block_toggle_hint": "You can setup blocking rules in the <a href='#filters'>Filters<\/a> settings.",
"use_adguard_browsing_sec": "Use AdGuard browsing security web service",
"use_adguard_browsing_sec_hint": "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.",
"use_adguard_parental": "Use AdGuard parental control web service",
"use_adguard_parental_hint": "AdGuard Home will check if domain contains adult materials. It uses the same privacy-friendly API as the browsing security web service.",
"enforce_safe_search": "Enforce safe search",
"enforce_save_search_hint": "AdGuard Home can enforce safe search in the following search engines: Google, Youtube, Bing, and Yandex.",
"no_servers_specified": "No servers specified",
"no_settings": "No settings",
"general_settings": "General settings",
"upstream_dns": "Upstream DNS servers",
"upstream_dns_hint": "If you keep this field empty, AdGuard Home will use <a href='https:\/\/1.1.1.1\/' target='_blank'>Cloudflare DNS<\/a> as an upstream. Use tls:\/\/ prefix for DNS over TLS servers.",
"test_upstream_btn": "Test upstreams",
"apply_btn": "Apply",
"disabled_filtering_toast": "Disabled filtering",
"enabled_filtering_toast": "Enabled filtering",
"disabled_safe_browsing_toast": "Disabled safebrowsing",
"enabled_safe_browsing_toast": "Enabled safebrowsing",
"disabled_parental_toast": "Disabled parental control",
"enabled_parental_toast": "Enabled parental control",
"disabled_safe_search_toast": "Disabled safe search",
"enabled_save_search_toast": "Enabled safe search",
"enabled_table_header": "Enabled",
"name_table_header": "Name",
"filter_url_table_header": "Filter URL",
"rules_count_table_header": "Rules count",
"last_time_updated_table_header": "Last time updated",
"actions_table_header": "Actions",
"delete_table_action": "Delete",
"filters_and_hosts": "Filters and hosts blocklists",
"filters_and_hosts_hint": "AdGuard Home understands basic adblock rules and hosts files syntax.",
"no_filters_added": "No filters added",
"add_filter_btn": "Add filter",
"cancel_btn": "Cancel",
"enter_name_hint": "Enter name",
"enter_url_hint": "Enter URL",
"check_updates_btn": "Check updates",
"new_filter_btn": "New filter subscription",
"enter_valid_filter_url": "Enter a valid URL to a filter subscription or a hosts file.",
"custom_filter_rules": "Custom filtering rules",
"custom_filter_rules_hint": "Enter one rule on a line. You can use either adblock rules or hosts files syntax.",
"examples_title": "Examples",
"example_meaning_filter_block": "block access to the example.org domain and all its subdomains",
"example_meaning_filter_whitelist": "unblock access to the example.org domain and all its subdomains",
"example_meaning_host_block": "AdGuard Home will now return 127.0.0.1 address for the example.org domain (but not its subdomains).",
"example_comment": "! Here goes a comment",
"example_comment_meaning": "just a comment",
"example_comment_hash": "# Also a comment",
"all_filters_up_to_date_toast": "All filters are already up-to-date",
"updated_upstream_dns_toast": "Updated the upstream DNS servers",
"dns_test_ok_toast": "Specified DNS servers are working correctly",
"dns_test_not_ok_toast": "Server '{{key}}': could not be used, please check that you've written it correctly",
"unblock_btn": "Unblock",
"block_btn": "Block",
"time_table_header": "Time",
"domain_name_table_header": "Domain name",
"type_table_header": "Type",
"response_table_header": "Response",
"empty_response_status": "Empty",
"show_all_filter_type": "Show all",
"show_filtered_type": "Show filtered",
"no_logs_found": "No logs found",
"disabled_log_btn": "Disable log",
"download_log_file_btn": "Download log file",
"refresh_btn": "Refresh",
"enabled_log_btn": "Enable log",
"last_dns_queries": "Last 5000 DNS queries",
"previous_btn": "Previous",
"next_btn": "Next",
"loading_table_status": "Loading...",
"page_table_footer_text": "Page",
"of_table_footer_text": "of",
"rows_table_footer_text": "rows",
"updated_custom_filtering_toast": "Updated the custom filtering rules",
"rule_removed_from_custom_filtering_toast": "Rule removed from the custom filtering rules",
"rule_added_to_custom_filtering_toast": "Rule added to the custom filtering rules",
"query_log_disabled_toast": "Query log disabled",
"query_log_enabled_toast": "Query log enabled",
"source_label": "Source",
"found_in_known_domain_db": "Found in the known domains database.",
"category_label": "Category",
"rule_label": "Rule",
"filter_label": "Filter"
}

View File

@ -1,135 +0,0 @@
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
copyright: 'Bản quyền',
homepage: 'Trang chủ',
report_an_issue: 'Báo lỗi',
// Dashboard
enable_protection: 'Bật bảo vệ',
enabled_protection: 'Đã bật bảo vệ',
disable_protection: 'Tắt bảo vệ',
disabled_protection: 'Đã tắt bảo vệ',
refresh_statics: 'Làm mới thống kê',
dns_query: 'Truy vấn DNS',
blocked_by: 'Chặn bởi',
stats_malware_phishing: 'Mã độc/lừa đảo đã chặn',
stats_adult: 'Website người lớn đã chặn',
stats_query_domain: 'Tên miền truy vấn nhiều',
for_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',
number_of_dns_query_24_hours: 'Số yêu cầu DNS đã xử lý trong 24 giờ qua',
number_of_dns_query_blocked_24_hours: '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',
number_of_dns_query_blocked_24_hours_by_sec: 'Số yêu cầu DNS bị chặn bởi chế độ bảo vệ duyệt web AdGuard',
number_of_dns_query_blocked_24_hours_adult: 'Số website người lớn đã chặn',
enforced_save_search: 'Tìm kiếm an toàn',
number_of_dns_query_to_safe_search: '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_processing_time_hint: 'Thời gian trung bình cho một yêu cầu DNS tính bằng mili giây',
// Settings
block_domain_use_filters_and_hosts: 'Chặn tên miền sử dụng các bộ lọc và file hosts',
filters_block_toggle_hint: 'Bạn có thể thiết lập quy tắc chặn tại cài đặt <a href="#filters">Bộ lọc</a>.',
use_adguard_browsing_sec: 'Sử dụng dịch vụ bảo vệ duyệt web AdGuard',
use_adguard_browsing_sec_hint: '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: 'Sử dụng dịch vụ quản lý của phụ huynh AdGuard',
use_adguard_parental_hint: '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',
enforce_save_search_hint: '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, Youtube, 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: 'Máy chủ DNS tìm kiếm',
upstream_dns_hint: 'Nếu bạn để trống mục này, AdGuard Home sẽ sử dụng <a href="https://1.1.1.1/" target="_blank">Cloudflare DNS</a> để tìm kiếm. Sử dụng tiền tố tls:// cho các máy chủ DNS dựa trên TLS.',
test_upstream_btn: 'Kiểm tra',
apply_btn: 'Áp dụng',
// Settings Toasts
disabled_filtering_toast: 'Đã tắt chặn quảng cáo',
enabled_filtering_toast: 'Đã bật chặn quảng cáo',
disabled_safe_browsing_toast: 'Đã tắt bảo vệ duyệt web',
enabled_safe_browsing_toast: 'Đã bật bảo vệ duyệt web',
disabled_parental_toast: 'Đã tắt quản lý của phụ huynh',
enabled_parental_toast: 'Đã bật quản lý của phụ huynh',
disabled_safe_search_toast: 'Đã tắt tìm kiếm an toàn',
enabled_save_search_toast: 'Đã bật tìm kiếm an toàn',
// Filters
enabled_table_header: 'Kích hoạt',
name_table_header: 'Tên',
filter_url_table_header: 'URL bộ lọc',
rules_count_table_header: 'Số quy tắc',
last_time_updated_table_header: 'Cập nhật cuối',
actions_table_header: 'Thao tác',
delete_table_action: 'Xoá',
filters_and_hosts: 'Danh sách bộ lọc và hosts',
filters_and_hosts_hint: '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_btn: 'Thêm bộ lọc',
cancel_btn: 'Huỷ',
enter_name_hint: 'Nhập tên',
enter_url_hint: 'Nhập URL',
check_updates_btn: 'Kiểm tra cập nhật',
new_filter_btn: 'Đăng ký bộ lọc mới',
enter_valid_filter_url: 'Nhập URL hợp lệ của bộ lọc hoặc file hosts',
custom_filter_rules: 'Quy tắc lọc tuỳ chỉnh',
custom_filter_rules_hint: '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_title: 'Ví dụ',
example_meaning_filter_block: 'Chặn truy cập tới tên miền example.org và tất cả tên miền con',
example_meaning_filter_whitelist: 'Không chặn truy cập tới tên miền example.org và tất cả tên miền con',
example_meaning_host_block: '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)',
example_comment: '! Đây là một chú thích',
example_comment_meaning: 'Chỉ là một chú thích',
example_comment_hash: '# Cũng là một chú thích',
all_filters_up_to_date_toast: 'Tất cả bộ lọc đã được cập nhật',
updated_upstream_dns_toast: 'Đã cập nhật máy chủ DNS tìm kiếm',
dns_test_ok_toast: 'Máy chủ DNS có thể sử dụng',
dns_test_not_ok_toast: 'Máy chủ "{{key}}": không thể sử dụng, vui lòng kiểm tra bạn đã điền chính xác',
// Logs
unblock_btn: 'Bỏ chặn',
block_btn: 'Chặn',
time_table_header: 'Thời gian',
domain_name_table_header: 'Tên miền',
type_table_header: 'Loại',
response_table_header: 'Phản hồi',
empty_response_status: 'Rỗng',
show_all_filter_type: 'Hiện tất cả',
show_filtered_type: 'Chỉ hiện đã chặn',
no_logs_found: 'Không có lịch sử truy vấn',
disabled_log_btn: 'Tắt lịch sử truy vấn',
download_log_file_btn: 'Tải tập tin lịch sử truy vấn',
refresh_btn: 'Làm mới',
enabled_log_btn: 'Bật lịch sử truy vấn',
last_5000_dns_queries: '5000 truy vấn DNS gần nhất',
previous_btn: 'Trang trước',
next_btn: 'Trang sau',
loading_table_status: 'Đang tải...',
page_table_footer_text: 'Trang',
of_table_footer_text: 'của',
rows_table_footer_text: 'hàng',
updated_custom_filtering_toast: 'Đã cập nhật quy tắc lọc tuỳ chỉnh',
rule_removed_from_custom_filtering_toast: 'Quy tắc đã được xoá khỏi quy tắc lọc tuỳ chỉnh',
rule_added_to_custom_filtering_toast: 'Quy tắc đã được thêm vào quy tắc lọc tuỳ chỉnh',
query_log_disabled_toast: 'Đã tắt lịch sử truy vấn',
query_log_enabled_toast: 'Đã bật lịch sử truy vấn',
// Popover
source_label: 'Nguồn',
found_in_known_domain_db: 'Tìm thấy trong cơ sở dữ liệu tên miền',
category_label: 'Thể loại',
// Popover filter
rule_label: 'Quy tắc',
filter_label: 'Bộ lọc',
},
};

View File

@ -0,0 +1,124 @@
{
"back": "Quay l\u1ea1i",
"dashboard": "T\u1ed5ng quan",
"settings": "C\u00e0i \u0111\u1eb7t",
"filters": "B\u1ed9 l\u1ecdc",
"query_log": "L\u1ecbch s\u1eed truy v\u1ea5n",
"faq": "H\u1ecfi \u0111\u00e1p",
"version": "phi\u00ean b\u1ea3n",
"address": "\u0111\u1ecba ch\u1ec9",
"on": "\u0110ang b\u1eadt",
"off": "\u0110ang t\u1eaft",
"copyright": "B\u1ea3n quy\u1ec1n",
"homepage": "Trang ch\u1ee7",
"report_an_issue": "B\u00e1o l\u1ed7i",
"enable_protection": "B\u1eadt b\u1ea3o v\u1ec7",
"enabled_protection": "\u0110\u00e3 b\u1eadt b\u1ea3o v\u1ec7",
"disable_protection": "T\u1eaft b\u1ea3o v\u1ec7",
"disabled_protection": "\u0110\u00e3 t\u1eaft b\u1ea3o v\u1ec7",
"refresh_statics": "L\u00e0m m\u1edbi th\u1ed1ng k\u00ea",
"dns_query": "Truy v\u1ea5n DNS",
"blocked_by": "Ch\u1eb7n b\u1edfi",
"stats_malware_phishing": "M\u00e3 \u0111\u1ed9c\/l\u1eeba \u0111\u1ea3o \u0111\u00e3 ch\u1eb7n",
"stats_adult": "Website ng\u01b0\u1eddi l\u1edbn \u0111\u00e3 ch\u1eb7n",
"stats_query_domain": "T\u00ean mi\u1ec1n truy v\u1ea5n nhi\u1ec1u",
"for_last_24_hours": "trong 24 gi\u1edd qua",
"no_domains_found": "Kh\u00f4ng c\u00f3 t\u00ean mi\u1ec1n n\u00e0o",
"requests_count": "S\u1ed1 l\u1ea7n y\u00eau c\u1ea7u",
"top_blocked_domains": "T\u00ean mi\u1ec1n ch\u1eb7n nhi\u1ec1u",
"top_clients": "Client d\u00f9ng nhi\u1ec1u",
"no_clients_found": "Kh\u00f4ng c\u00f3 client n\u00e0o",
"general_statistics": "Th\u1ed1ng k\u00ea chung",
"number_of_dns_query_24_hours": "S\u1ed1 y\u00eau c\u1ea7u DNS \u0111\u00e3 x\u1eed l\u00fd trong 24 gi\u1edd qua",
"number_of_dns_query_blocked_24_hours": "S\u1ed1 y\u00eau c\u1ea7u DNS b\u1ecb ch\u1eb7n b\u1edfi b\u1ed9 l\u1ecdc qu\u1ea3ng c\u00e1o v\u00e0 danh s\u00e1ch ch\u1eb7n host",
"number_of_dns_query_blocked_24_hours_by_sec": "S\u1ed1 y\u00eau c\u1ea7u DNS b\u1ecb ch\u1eb7n b\u1edfi ch\u1ebf \u0111\u1ed9 b\u1ea3o v\u1ec7 duy\u1ec7t web AdGuard",
"number_of_dns_query_blocked_24_hours_adult": "S\u1ed1 website ng\u01b0\u1eddi l\u1edbn \u0111\u00e3 ch\u1eb7n",
"enforced_save_search": "T\u00ecm ki\u1ebfm an to\u00e0n",
"number_of_dns_query_to_safe_search": "S\u1ed1 y\u00eau c\u1ea7u DNS t\u1edbi c\u00f4ng c\u1ee5 t\u00ecm ki\u1ebfm \u0111\u00e3 chuy\u1ec3n th\u00e0nh t\u00ecm ki\u1ebfm an to\u00e0n",
"average_processing_time": "Th\u1eddi gian x\u1eed l\u00fd trung b\u00ecnh",
"average_processing_time_hint": "Th\u1eddi gian trung b\u00ecnh cho m\u1ed9t y\u00eau c\u1ea7u DNS t\u00ednh b\u1eb1ng mili gi\u00e2y",
"block_domain_use_filters_and_hosts": "Ch\u1eb7n t\u00ean mi\u1ec1n s\u1eed d\u1ee5ng c\u00e1c b\u1ed9 l\u1ecdc v\u00e0 file hosts",
"filters_block_toggle_hint": "B\u1ea1n c\u00f3 th\u1ec3 thi\u1ebft l\u1eadp quy t\u1eafc ch\u1eb7n t\u1ea1i c\u00e0i \u0111\u1eb7t <a href='#filters'>B\u1ed9 l\u1ecdc<\/a>.",
"use_adguard_browsing_sec": "S\u1eed d\u1ee5ng d\u1ecbch v\u1ee5 b\u1ea3o v\u1ec7 duy\u1ec7t web AdGuard",
"use_adguard_browsing_sec_hint": "AdGuard Home s\u1ebd ki\u1ec3m tra t\u00ean mi\u1ec1n v\u1edbi d\u1ecbch v\u1ee5 b\u1ea3o v\u1ec7 duy\u1ec7t web. T\u00ednh n\u0103ng s\u1eed d\u1ee5ng m\u1ed9t API th\u00e2n thi\u1ec7n v\u1edbi quy\u1ec1n ri\u00eang t\u01b0: ch\u1ec9 m\u1ed9t ph\u1ea7n ng\u1eafn ti\u1ec1n t\u1ed1 m\u00e3 b\u0103m SHA256 \u0111\u01b0\u1ee3c g\u1eedi \u0111\u1ebfn m\u00e1y ch\u1ee7",
"use_adguard_parental": "S\u1eed d\u1ee5ng d\u1ecbch v\u1ee5 qu\u1ea3n l\u00fd c\u1ee7a ph\u1ee5 huynh AdGuard",
"use_adguard_parental_hint": "AdGuard Home s\u1ebd ki\u1ec3m tra n\u1ebfu t\u00ean mi\u1ec1n ch\u1ee9a t\u1eeb kho\u00e1 ng\u01b0\u1eddi l\u1edbn. T\u00ednh n\u0103ng s\u1eed d\u1ee5ng API th\u00e2n thi\u1ec7n v\u1edbi quy\u1ec1n ri\u00eang t\u01b0 t\u01b0\u01a1ng t\u1ef1 v\u1edbi d\u1ecbch v\u1ee5 b\u1ea3o v\u1ec7 duy\u1ec7t web",
"enforce_safe_search": "B\u1eaft bu\u1ed9c t\u00ecm ki\u1ebfm an to\u00e0n",
"enforce_save_search_hint": "AdGuard Home c\u00f3 th\u1ec3 b\u1eaft bu\u1ed9c t\u00ecm ki\u1ebfm an to\u00e0n v\u1edbi c\u00e1c d\u1ecbch v\u1ee5 t\u00ecm ki\u1ebfm: Google, Youtube, Bing, Yandex.",
"no_servers_specified": "Kh\u00f4ng c\u00f3 m\u00e1y ch\u1ee7 n\u00e0o \u0111\u01b0\u1ee3c li\u1ec7t k\u00ea",
"no_settings": "Kh\u00f4ng c\u00f3 c\u00e0i \u0111\u1eb7t n\u00e0o",
"general_settings": "C\u00e0i \u0111\u1eb7t chung",
"upstream_dns": "M\u00e1y ch\u1ee7 DNS t\u00ecm ki\u1ebfm",
"upstream_dns_hint": "N\u1ebfu b\u1ea1n \u0111\u1ec3 tr\u1ed1ng m\u1ee5c n\u00e0y, AdGuard Home s\u1ebd s\u1eed d\u1ee5ng <a href='https:\/\/1.1.1.1\/' target='_blank'>Cloudflare DNS<\/a> \u0111\u1ec3 t\u00ecm ki\u1ebfm. S\u1eed d\u1ee5ng ti\u1ec1n t\u1ed1 tls:\/\/ cho c\u00e1c m\u00e1y ch\u1ee7 DNS d\u1ef1a tr\u00ean TLS.",
"test_upstream_btn": "Ki\u1ec3m tra",
"apply_btn": "\u00c1p d\u1ee5ng",
"disabled_filtering_toast": "\u0110\u00e3 t\u1eaft ch\u1eb7n qu\u1ea3ng c\u00e1o",
"enabled_filtering_toast": "\u0110\u00e3 b\u1eadt ch\u1eb7n qu\u1ea3ng c\u00e1o",
"disabled_safe_browsing_toast": "\u0110\u00e3 t\u1eaft b\u1ea3o v\u1ec7 duy\u1ec7t web",
"enabled_safe_browsing_toast": "\u0110\u00e3 b\u1eadt b\u1ea3o v\u1ec7 duy\u1ec7t web",
"disabled_parental_toast": "\u0110\u00e3 t\u1eaft qu\u1ea3n l\u00fd c\u1ee7a ph\u1ee5 huynh",
"enabled_parental_toast": "\u0110\u00e3 b\u1eadt qu\u1ea3n l\u00fd c\u1ee7a ph\u1ee5 huynh",
"disabled_safe_search_toast": "\u0110\u00e3 t\u1eaft t\u00ecm ki\u1ebfm an to\u00e0n",
"enabled_save_search_toast": "\u0110\u00e3 b\u1eadt t\u00ecm ki\u1ebfm an to\u00e0n",
"enabled_table_header": "K\u00edch ho\u1ea1t",
"name_table_header": "T\u00ean",
"filter_url_table_header": "URL b\u1ed9 l\u1ecdc",
"rules_count_table_header": "S\u1ed1 quy t\u1eafc",
"last_time_updated_table_header": "C\u1eadp nh\u1eadt cu\u1ed1i",
"actions_table_header": "Thao t\u00e1c",
"delete_table_action": "Xo\u00e1",
"filters_and_hosts": "Danh s\u00e1ch b\u1ed9 l\u1ecdc v\u00e0 hosts",
"filters_and_hosts_hint": "AdGuard home hi\u1ec3u c\u00e1c quy t\u1eafc ch\u1eb7n qu\u1ea3ng c\u00e1o \u0111\u01a1n gi\u1ea3n v\u00e0 c\u00fa ph\u00e1p file hosts",
"no_filters_added": "Kh\u00f4ng c\u00f3 b\u1ed9 l\u1ecdc n\u00e0o \u0111\u01b0\u1ee3c th\u00eam",
"add_filter_btn": "Th\u00eam b\u1ed9 l\u1ecdc",
"cancel_btn": "Hu\u1ef7",
"enter_name_hint": "Nh\u1eadp t\u00ean",
"enter_url_hint": "Nh\u1eadp URL",
"check_updates_btn": "Ki\u1ec3m tra c\u1eadp nh\u1eadt",
"new_filter_btn": "\u0110\u0103ng k\u00fd b\u1ed9 l\u1ecdc m\u1edbi",
"enter_valid_filter_url": "Nh\u1eadp URL h\u1ee3p l\u1ec7 c\u1ee7a b\u1ed9 l\u1ecdc ho\u1eb7c file hosts",
"custom_filter_rules": "Quy t\u1eafc l\u1ecdc tu\u1ef3 ch\u1ec9nh",
"custom_filter_rules_hint": "Nh\u1eadp m\u1ed7i quy t\u1eafc 1 d\u00f2ng. C\u00f3 th\u1ec3 s\u1eed d\u1ee5ng quy t\u1eafc ch\u1eb7n qu\u1ea3ng c\u00e1o ho\u1eb7c c\u00fa ph\u00e1p file host",
"examples_title": "V\u00ed d\u1ee5",
"example_meaning_filter_block": "Ch\u1eb7n truy c\u1eadp t\u1edbi t\u00ean mi\u1ec1n example.org v\u00e0 t\u1ea5t c\u1ea3 t\u00ean mi\u1ec1n con",
"example_meaning_filter_whitelist": "Kh\u00f4ng ch\u1eb7n truy c\u1eadp t\u1edbi t\u00ean mi\u1ec1n example.org v\u00e0 t\u1ea5t c\u1ea3 t\u00ean mi\u1ec1n con",
"example_meaning_host_block": "AdGuard Home s\u1ebd ph\u1ea3n h\u1ed3i \u0111\u1ecba ch\u1ec9 IP 127.0.0.1 cho t\u00ean mi\u1ec1n example.org (kh\u00f4ng \u00e1p d\u1ee5ng t\u00ean mi\u1ec1n con)",
"example_comment": "! \u0110\u00e2y l\u00e0 m\u1ed9t ch\u00fa th\u00edch",
"example_comment_meaning": "Ch\u1ec9 l\u00e0 m\u1ed9t ch\u00fa th\u00edch",
"example_comment_hash": "# C\u0169ng l\u00e0 m\u1ed9t ch\u00fa th\u00edch",
"all_filters_up_to_date_toast": "T\u1ea5t c\u1ea3 b\u1ed9 l\u1ecdc \u0111\u00e3 \u0111\u01b0\u1ee3c c\u1eadp nh\u1eadt",
"updated_upstream_dns_toast": "\u0110\u00e3 c\u1eadp nh\u1eadt m\u00e1y ch\u1ee7 DNS t\u00ecm ki\u1ebfm",
"dns_test_ok_toast": "M\u00e1y ch\u1ee7 DNS c\u00f3 th\u1ec3 s\u1eed d\u1ee5ng",
"dns_test_not_ok_toast": "M\u00e1y ch\u1ee7 '{{key}}': kh\u00f4ng th\u1ec3 s\u1eed d\u1ee5ng, vui l\u00f2ng ki\u1ec3m tra b\u1ea1n \u0111\u00e3 \u0111i\u1ec1n ch\u00ednh x\u00e1c",
"unblock_btn": "B\u1ecf ch\u1eb7n",
"block_btn": "Ch\u1eb7n",
"time_table_header": "Th\u1eddi gian",
"domain_name_table_header": "T\u00ean mi\u1ec1n",
"type_table_header": "Lo\u1ea1i",
"response_table_header": "Ph\u1ea3n h\u1ed3i",
"empty_response_status": "R\u1ed7ng",
"show_all_filter_type": "Hi\u1ec7n t\u1ea5t c\u1ea3",
"show_filtered_type": "Ch\u1ec9 hi\u1ec7n \u0111\u00e3 ch\u1eb7n",
"no_logs_found": "Kh\u00f4ng c\u00f3 l\u1ecbch s\u1eed truy v\u1ea5n",
"disabled_log_btn": "T\u1eaft l\u1ecbch s\u1eed truy v\u1ea5n",
"download_log_file_btn": "T\u1ea3i t\u1eadp tin l\u1ecbch s\u1eed truy v\u1ea5n",
"refresh_btn": "L\u00e0m m\u1edbi",
"enabled_log_btn": "B\u1eadt l\u1ecbch s\u1eed truy v\u1ea5n",
"last_dns_queries": "5000 truy v\u1ea5n DNS g\u1ea7n nh\u1ea5t",
"previous_btn": "Trang tr\u01b0\u1edbc",
"next_btn": "Trang sau",
"loading_table_status": "\u0110ang t\u1ea3i...",
"page_table_footer_text": "Trang",
"of_table_footer_text": "c\u1ee7a",
"rows_table_footer_text": "h\u00e0ng",
"updated_custom_filtering_toast": "\u0110\u00e3 c\u1eadp nh\u1eadt quy t\u1eafc l\u1ecdc tu\u1ef3 ch\u1ec9nh",
"rule_removed_from_custom_filtering_toast": "Quy t\u1eafc \u0111\u00e3 \u0111\u01b0\u1ee3c xo\u00e1 kh\u1ecfi quy t\u1eafc l\u1ecdc tu\u1ef3 ch\u1ec9nh",
"rule_added_to_custom_filtering_toast": "Quy t\u1eafc \u0111\u00e3 \u0111\u01b0\u1ee3c th\u00eam v\u00e0o quy t\u1eafc l\u1ecdc tu\u1ef3 ch\u1ec9nh",
"query_log_disabled_toast": "\u0110\u00e3 t\u1eaft l\u1ecbch s\u1eed truy v\u1ea5n",
"query_log_enabled_toast": "\u0110\u00e3 b\u1eadt l\u1ecbch s\u1eed truy v\u1ea5n",
"source_label": "Ngu\u1ed3n",
"found_in_known_domain_db": "T\u00ecm th\u1ea5y trong c\u01a1 s\u1edf d\u1eef li\u1ec7u t\u00ean mi\u1ec1n",
"category_label": "Th\u1ec3 lo\u1ea1i",
"rule_label": "Quy t\u1eafc",
"filter_label": "B\u1ed9 l\u1ecdc"
}

View File

@ -298,7 +298,7 @@ class Logs extends Component {
const { queryLogEnabled } = dashboard;
return (
<Fragment>
<PageTitle title={ t('query_log') } subtitle={ t('last_5000_dns_queries') }>
<PageTitle title={ t('query_log') } subtitle={ t('last_dns_queries') }>
<div className="page-title__actions">
{this.renderButtons(queryLogEnabled)}
</div>

View File

@ -0,0 +1,107 @@
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const requestPromise = require('request-promise');
const LOCALES_DIR = '../../__locales';
const LOCALES_LIST = ['en', 'ru', 'vi'];
/**
* Hash content
* @param {string} content
*/
const hashString = content => crypto.createHash('md5').update(content, 'utf8').digest('hex');
/**
* Prepare params to get translations from oneskyapp
* @param {string} locale language shortcut
* @param {object} oneskyapp config oneskyapp
*/
const prepare = (locale, oneskyapp) => {
const timestamp = Math.round(new Date().getTime() / 1000);
let url = [];
url.push(oneskyapp.url + oneskyapp.projectId);
url.push(`/translations?locale=${locale}`);
url.push('&source_file_name=en.json');
url.push(`&export_file_name=${locale}.json`);
url.push(`&api_key=${oneskyapp.apiKey}`);
url.push(`&timestamp=${timestamp}`);
url.push(`&dev_hash=${hashString(timestamp + oneskyapp.secretKey)}`);
url = url.join('');
return url;
};
/**
* Promise wrapper for writing in file
* @param {string} filename
* @param {any} body
*/
function writeInFile(filename, body) {
return new Promise((resolve, reject) => {
if (typeof body !== 'string') {
try {
body = JSON.stringify(body, null, 4); // eslint-disable-line
} catch (err) {
reject(err);
}
}
fs.writeFile(filename, body, (err) => {
if (err) reject(err);
resolve('Ok');
});
});
}
/**
* Request to server onesky
* @param {string} url
* @param {string} locale
*/
const request = (url, locale) => (
requestPromise.get(url)
.then((res) => {
if (res.length) {
const pathToFile = path.join(LOCALES_DIR, `${locale}.json`);
return writeInFile(pathToFile, res);
}
return null;
})
.then((res) => {
let result = locale;
result += res ? ' - OK' : ' - Empty';
return result;
})
.catch((err) => {
console.log(err);
return `${locale} - Not OK`;
}));
/**
* Download locales
*/
const download = () => {
const locales = LOCALES_LIST;
let oneskyapp;
try {
oneskyapp = JSON.parse(fs.readFileSync('./oneskyapp.json'));
} catch (err) {
throw new Error(err);
}
const requests = locales.map((locale) => {
const url = prepare(locale, oneskyapp);
return request(url, locale);
});
Promise
.all(requests)
.then((res) => {
res.forEach(item => console.log(item));
})
.catch(err => console.log(err));
};
download();

View File

@ -0,0 +1,6 @@
{
"url": "https://platform.api.onesky.io/1/projects/",
"projectId": "<PROJECT ID>",
"apiKey": "<API KEY>",
"secretKey": "<SECRET KEY>"
}

View File

@ -0,0 +1,61 @@
{
"name": "translations",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"bluebird": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
"integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw=="
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
"psl": {
"version": "1.1.29",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
"integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
},
"request-promise": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
"integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
"requires": {
"bluebird": "^3.5.0",
"request-promise-core": "1.1.1",
"stealthy-require": "^1.1.0",
"tough-cookie": ">=2.3.3"
}
},
"request-promise-core": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
"integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
"requires": {
"lodash": "^4.13.1"
}
},
"stealthy-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
},
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"requires": {
"psl": "^1.1.24",
"punycode": "^1.4.1"
}
}
}
}

View File

@ -0,0 +1,12 @@
{
"name": "translations",
"version": "0.1.0",
"private": true,
"scripts": {
"download-locales": "node download.js",
"upload-locales": "node upload.js"
},
"dependencies": {
"request-promise": "^4.2.2"
}
}

View File

@ -0,0 +1,51 @@
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const request = require('request-promise');
const LOCALES_DIR = '../../__locales';
/**
* Hash content
*
* @param {string} content
*/
const hashString = content => crypto.createHash('md5').update(content, 'utf8').digest('hex');
/**
* Prepare post params
*/
const prepare = () => {
let oneskyapp;
try {
oneskyapp = JSON.parse(fs.readFileSync('./oneskyapp.json'));
} catch (err) {
throw new Error(err);
}
const url = `${oneskyapp.url}${oneskyapp.projectId}/files`;
const timestamp = Math.round(new Date().getTime() / 1000);
const formData = {
timestamp,
file: fs.createReadStream(path.resolve(LOCALES_DIR, 'en.json')),
file_format: 'HIERARCHICAL_JSON',
locale: 'en',
is_keeping_all_strings: 'false',
api_key: oneskyapp.apiKey,
dev_hash: hashString(timestamp + oneskyapp.secretKey),
};
return { url, formData };
};
/**
* Make request to onesky to upload new json
*/
const upload = () => {
const { url, formData } = prepare();
request
.post({ url, formData })
.catch(err => console.log(err));
};
upload();

View File

@ -1,31 +1,38 @@
import i18n from 'i18next';
import { reactI18nextModule } from 'react-i18next';
import { initReactI18n } from 'react-i18next/hooks';
import langDetect from 'i18next-browser-languagedetector';
import vi from './__locales/vi';
import en from './__locales/en';
import vi from './__locales/vi.json';
import en from './__locales/en.json';
export const languages = [
{
key: 'en',
name: 'English',
},
{
key: 'vi',
name: 'Tiếng Việt',
},
{
key: 'en',
name: 'English',
key: 'ru',
name: 'Русский',
},
];
i18n
.use(langDetect)
.use(initReactI18n)
.use(reactI18nextModule) // passes i18n down to react-i18next
.init({
resources: {
vi,
en,
vi: {
translation: vi,
},
en: {
translation: en,
},
},
fallbackLng: 'en',
keySeparator: false, // we use content as keys