Merge pull request #487 from cmandesign/feature/fa-lang-rtl

Feature/fa lang rtl
This commit is contained in:
Louis Lam 2021-10-01 16:28:20 +08:00 committed by GitHub
commit 9d079eeec0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 272 additions and 8 deletions

View file

@ -67,6 +67,8 @@
"nodemailer": "^6.6.5", "nodemailer": "^6.6.5",
"notp": "^2.0.3", "notp": "^2.0.3",
"password-hash": "^1.2.2", "password-hash": "^1.2.2",
"postcss-rtlcss": "^3.4.1",
"postcss-scss": "^4.0.0",
"prom-client": "^13.2.0", "prom-client": "^13.2.0",
"prometheus-api-metrics": "^3.2.0", "prometheus-api-metrics": "^3.2.0",
"qrcode": "^1.4.4", "qrcode": "^1.4.4",

View file

@ -3,5 +3,10 @@
</template> </template>
<script> <script>
export default {} import { setPageLocale } from "./util-frontend";
export default {
created() {
setPageLocale();
},
};
</script> </script>

View file

@ -410,3 +410,7 @@ h2 {
.vue-image-crop-upload .vicp-wrap { .vue-image-crop-upload .vicp-wrap {
border-radius: 10px !important; border-radius: 10px !important;
} }
// Localization
@import "localization.scss";

View file

@ -0,0 +1,5 @@
html[lang='fa'] {
#app {
font-family: 'IRANSans', 'Iranian Sans','B Nazanin', 'Tahoma', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, segoe ui, Roboto, helvetica neue, Arial, noto sans, sans-serif, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji;
}
}

View file

@ -3,6 +3,7 @@ import bgBG from "./languages/bg-BG";
import daDK from "./languages/da-DK"; import daDK from "./languages/da-DK";
import deDE from "./languages/de-DE"; import deDE from "./languages/de-DE";
import en from "./languages/en"; import en from "./languages/en";
import fa from "./languages/fa";
import esEs from "./languages/es-ES"; import esEs from "./languages/es-ES";
import ptBR from "./languages/pt-BR"; import ptBR from "./languages/pt-BR";
import etEE from "./languages/et-EE"; import etEE from "./languages/et-EE";
@ -27,6 +28,7 @@ const languageList = {
"de-DE": deDE, "de-DE": deDE,
"nl-NL": nlNL, "nl-NL": nlNL,
"es-ES": esEs, "es-ES": esEs,
"fa": fa,
"pt-BR": ptBR, "pt-BR": ptBR,
"fr-FR": frFR, "fr-FR": frFR,
"it-IT": itIT, "it-IT": itIT,
@ -43,8 +45,15 @@ const languageList = {
"et-EE": etEE, "et-EE": etEE,
}; };
const rtlLangs = ["fa"];
export const currentLocale = () => localStorage.locale || "en";
export const localeDirection = () => {
return rtlLangs.includes(currentLocale()) ? "rtl" : "ltr"
}
export const i18n = createI18n({ export const i18n = createI18n({
locale: localStorage.locale || "en", locale: currentLocale(),
fallbackLocale: "en", fallbackLocale: "en",
silentFallbackWarn: true, silentFallbackWarn: true,
silentTranslationWarn: true, silentTranslationWarn: true,

190
src/languages/fa.js Normal file
View file

@ -0,0 +1,190 @@
export default {
languageName: "Farsi",
checkEverySecond: "بررسی هر {0} ثانیه.",
retryCheckEverySecond: "تکرار مجدد هر {0} ثانیه.",
retriesDescription: "حداکثر تعداد تکرار پیش از علامت گذاری وب‌سایت بعنوان خارج از دسترس و ارسال اطلاع‌رسانی.",
ignoreTLSError: "بی‌خیال ارور TLS/SSL برای سایت‌های HTTPS",
upsideDownModeDescription: "نتیجه وضعیت را برعکس کن، مثلا اگر سرویس در دسترس بود فرض کن که سرویس پایین است!",
maxRedirectDescription: "حداکثر تعداد ریدایرکتی که سرویس پشتیبانی کند. برای اینکه ری‌دایرکت‌ها پشتیبانی نشوند، عدد 0 را وارد کنید.",
acceptedStatusCodesDescription: "لطفا HTTP Status Code هایی که میخواهید به عنوان پاسخ موفقیت آمیز در نظر گرفته شود را انتخاب کنید.",
passwordNotMatchMsg: "تکرار رمز عبور مطابقت ندارد!",
notificationDescription: "برای اینکه سرویس اطلاع‌رسانی کار کند، آنرا به یکی از مانیتور‌ها متصل کنید.",
keywordDescription: "در نتیجه درخواست (اهمیتی ندارد پاسخ JSON است یا HTML) بدنبال این کلمه بگرد (حساس به کوچک/بزرگ بودن حروف).",
pauseDashboardHome: "متوقف شده",
deleteMonitorMsg: "آیا از حذف این مانیتور مطمئن هستید؟",
deleteNotificationMsg: "آیا مطمئن هستید که میخواهید این سرویس اطلاع‌رسانی را برای تمامی مانیتورها حذف کنید؟",
resoverserverDescription: "سرویس CloudFlare به عنوان سرور پیش‌فرض استفاده می‌شود، شما میتوانید آنرا به هر سرور دیگری بعدا تغییر دهید.",
rrtypeDescription: "لطفا نوع Resource Record را انتخاب کنید.",
pauseMonitorMsg: "آیا مطمئن هستید که میخواهید این مانیتور را متوقف کنید ؟",
enableDefaultNotificationDescription: "برای هر مانیتور جدید، این سرویس اطلاع‌رسانی به صورت پیش‌فرض فعال خواهد شد. البته که شما میتوانید به صورت دستی آنرا برای هر مانیتور به صورت جداگانه غیر فعال کنید.",
clearEventsMsg: "آیا از اینکه تمامی تاریخچه رویداد‌های این مانیتور حذف شود مطمئن هستید؟",
clearHeartbeatsMsg: "آیا از اینکه تاریخچه تمامی Heartbeat های این مانیتور حذف شود مطمئن هستید؟ ",
confirmClearStatisticsMsg: "آیا از حذف تمامی آمار و ارقام مطمئن هستید؟",
importHandleDescription: " اگر که میخواهید بیخیال مانیتورها و یا سرویس‌های اطلاع‌رسانی که با نام مشابه از قبل موجود هستند شوید، گزینه 'بی‌خیال موارد ..' را انتخاب کنید. توجه کنید که گزینه 'بازنویسی' تمامی موارد موجود با نام مشابه را از بین خواهد برد.",
confirmImportMsg: "آیا از بازگردانی بک آپ مطمئن هستید؟ لطفا از اینکه نوع بازگردانی درستی را انتخاب کرده‌اید اطمینان حاصل کنید!",
twoFAVerifyLabel: "لطفا جهت اطمینان از عملکرد احراز هویت دو مرحله‌ای توکن خود را وارد کنید!",
tokenValidSettingsMsg: "توکن شما معتبر است، هم اکنون میتوانید احراز هویت دو مرحله‌ای را فعال کنید!",
confirmEnableTwoFAMsg: " آیا از فعال سازی احراز هویت دو مرحله‌ای مطمئن هستید؟",
confirmDisableTwoFAMsg: "آیا از غیرفعال سازی احراز هویت دومرحله‌ای مطمئن هستید؟",
Settings: "تنظیمات",
Dashboard: "پیشخوان",
"New Update": "بروزرسانی جدید!",
Language: "زبان",
Appearance: "ظاهر",
Theme: "پوسته",
General: "عمومی",
Version: "نسخه",
"Check Update On GitHub": "بررسی بروزرسانی بر روی گیت‌هاب",
List: "لیست",
Add: "اضافه",
"Add New Monitor": "اضافه کردن مانیتور جدید",
"Quick Stats": "خلاصه وضعیت",
Up: "فعال",
Down: "غیرفعال",
Pending: "در انتظار تایید",
Unknown: "نامشخص",
Pause: "توقف",
Name: "نام",
Status: "وضعیت",
DateTime: "تاریخ و زمان",
Message: "پیام",
"No important events": "رخداد جدیدی موجود نیست.",
Resume: "ادامه",
Edit: "ویرایش",
Delete: "حذف",
Current: "فعلی",
Uptime: "آپتایم",
"Cert Exp.": "تاریخ انقضای SSL",
days: "روز",
day: "روز",
"-day": "-روز",
hour: "ساعت",
"-hour": "-ساعت",
Response: "پاسخ",
Ping: "Ping",
"Monitor Type": "نوع مانیتور",
Keyword: "کلمه کلیدی",
"Friendly Name": "عنوان",
URL: "آدرس (URL)",
Hostname: "نام میزبان (Hostname)",
Port: "پورت",
"Heartbeat Interval": "فاصله هر Heartbeat",
Retries: "تلاش مجدد",
"Heartbeat Retry Interval": "فاصله تلاش مجدد برایHeartbeat",
Advanced: "پیشرفته",
"Upside Down Mode": "حالت بر عکس",
"Max. Redirects": "حداکثر تعداد ری‌دایرکت",
"Accepted Status Codes": "وضعیت‌های (Status Code) های قابل قبول",
Save: "ذخیره",
Notifications: "اطلاع‌رسانی‌ها",
"Not available, please setup.": "هیچ موردی موجود نیست، اولین مورد را راه اندازی کنید!",
"Setup Notification": "راه اندازی اطلاع‌رسانی‌",
Light: "روشن",
Dark: "تاریک",
Auto: "اتوماتیک",
"Theme - Heartbeat Bar": "ظاهر نوار Heartbeat",
Normal: "معمولی",
Bottom: "پایین",
None: "هیچ کدام",
Timezone: "موقعیت زمانی",
"Search Engine Visibility": "قابلیت دسترسی برای موتورهای جستجو",
"Allow indexing": "اجازه ایندکس شدن را بده.",
"Discourage search engines from indexing site": "به موتورهای جستجو اجازه ایندکس کردن این سامانه را نده.",
"Change Password": "تغییر رمزعبور",
"Current Password": "رمزعبور فعلی",
"New Password": "رمزعبور جدید",
"Repeat New Password": "تکرار رمزعبور جدید",
"Update Password": "بروز رسانی رمز عبور",
"Disable Auth": "غیر فعال سازی تایید هویت",
"Enable Auth": "فعال سازی تایید هویت",
Logout: "خروج",
Leave: "منصرف شدم",
"I understand, please disable": "متوجه هستم، لطفا غیرفعال کنید!",
Confirm: "تایید",
Yes: "بلی",
No: "خیر",
Username: "نام کاربری",
Password: "کلمه عبور",
"Remember me": "مراب هب خاطر بسپار",
Login: "ورود",
"No Monitors, please": "هیچ مانیتوری موجود نیست، لطفا",
"add one": "یک مورد اضافه کنید",
"Notification Type": "نوع اطلاع‌رسانی",
Email: "ایمیل",
Test: "تست",
"Certificate Info": "اطلاعات سرتیفیکت",
"Resolver Server": "سرور Resolver",
"Resource Record Type": "نوع رکورد (Resource Record Type)",
"Last Result": "آخرین نتیجه",
"Create your admin account": "ایجاد حساب کاربری مدیر",
"Repeat Password": "تکرار رمز عبور",
"Import Backup": "بازگردانی فایل پشتیبان",
"Export Backup": "ذخیره فایل پشتیبان",
Export: "استخراج اطلاعات",
Import: "ورود اطلاعات",
respTime: "زمان پاسخگویی (میلی‌ثانیه)",
notAvailableShort: "ناموجود",
"Default enabled": "به صورت پیش‌فرض فعال باشد.",
"Apply on all existing monitors": "بر روی تمامی مانیتور‌های فعلی اعمال شود.",
Create: "ایجاد",
"Clear Data": "پاکسازی داده‌ها",
Events: "رخداد‌ها",
Heartbeats: "Heartbeats",
"Auto Get": "Auto Get",
backupDescription: "شما میتوانید تمامی مانیتورها و تنظیمات اطلاع‌رسانی‌ها را در قالب یه فایل JSON دریافت کنید.",
backupDescription2: "البته تاریخچه رخدادها دراین فایل قرار نخواهند داشت.",
backupDescription3: "توجه داشته باشید که تمامی اطلاعات حساس شما مانند توکن‌ها نیز در این فایل وجود خواهد داشت ، پس از این فایل به خوبی مراقبت کنید.",
alertNoFile: "لطفا یک فایل برای «ورود اطلاعات» انتخاب کنید..",
alertWrongFileType: "یک فایل JSON انتخاب کنید.",
"Clear all statistics": "پاکسازی تمامی آمار و ارقام",
"Skip existing": "بی‌خیال مواردی که از قبل موجود است",
Overwrite: "بازنویسی",
Options: "تنظیمات",
"Keep both": "هر دو را نگه‌ دار",
"Verify Token": "تایید توکن",
"Setup 2FA": "تنظیمات احراز دو مرحله‌ای",
"Enable 2FA": "فعال سازی احراز 2 مرحله‌ای",
"Disable 2FA": "غیر فعال کردن احراز 2 مرحله‌ای",
"2FA Settings": "تنظیمات احراز 2 مرحله‌ای",
"Two Factor Authentication": "احراز هویت دومرحله‌ای",
Active: "فعال",
Inactive: "غیرفعال",
Token: "توکن",
"Show URI": "نمایش آدرس (URI) ",
Tags: "برچسب‌ها",
"Add New below or Select...": "یک مورد جدید اضافه کنید و یا از لیست انتخاب کنید...",
"Tag with this name already exist.": "یک برچسب با این «نام» از قبل وجود دارد",
"Tag with this value already exist.": "یک برچسب با این «مقدار» از قبل وجود دارد.",
color: "رنگ",
"value (optional)": "مقدار (اختیاری)",
Gray: "خاکستری",
Red: "قرمز",
Orange: "نارنجی",
Green: "سبز",
Blue: "آبی",
Indigo: "نیلی",
Purple: "بنفش",
Pink: "صورتی",
"Search...": "جستجو...",
"Avg. Ping": "متوسط پینگ",
"Avg. Response": "متوسط زمان پاسخ",
"Entry Page": "صفحه ورودی",
statusPageNothing: "چیزی اینجا نیست، لطفا یک گروه و یا یک مانیتور اضافه کنید!",
"No Services": "هیچ سرویسی موجود نیست",
"All Systems Operational": "تمامی سیستم‌ها عملیاتی هستند!",
"Partially Degraded Service": "افت نسبی کیفیت سرویس",
"Degraded Service": "افت کامل کیفیت سرویس",
"Add Group": "اضافه کردن گروه",
"Add a monitor": "اضافه کردن مانیتور",
"Edit Status Page": "ویرایش صفحه وضعیت",
"Status Page": "صفحه وضعیت",
"Go to Dashboard": "رفتن به پیشخوان",
"Uptime Kuma": "آپتایم کوما",
records: "مورد",
"One record": "یک مورد",
"Showing {from} to {to} of {count} records": "نمایش از {from} تا {to} از {count} مورد",
First: "اولین",
Last: "آخرین",
Info: "اطلاعات",
"Powered By": "نیرو گرفته از",
};

View file

@ -10,7 +10,7 @@
<header v-if="! $root.isMobile" class="d-flex flex-wrap justify-content-center py-3 mb-3 border-bottom"> <header v-if="! $root.isMobile" class="d-flex flex-wrap justify-content-center py-3 mb-3 border-bottom">
<router-link to="/dashboard" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none"> <router-link to="/dashboard" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
<object class="bi me-2 ms-4" width="40" height="40" data="/icon.svg" /> <object class="bi me-2 ms-4" width="40" height="40" data="/icon.svg" />
<span class="fs-4 title">Uptime Kuma</span> <span class="fs-4 title">{{ $t("Uptime Kuma") }}</span>
</router-link> </router-link>
<a v-if="hasNewVersion" target="_blank" href="https://github.com/louislam/uptime-kuma/releases" class="btn btn-info me-3"> <a v-if="hasNewVersion" target="_blank" href="https://github.com/louislam/uptime-kuma/releases" class="btn btn-info me-3">

View file

@ -57,6 +57,7 @@
v-model="page" v-model="page"
:records="importantHeartBeatList.length" :records="importantHeartBeatList.length"
:per-page="perPage" :per-page="perPage"
:options="paginationConfig"
/> />
</div> </div>
</div> </div>
@ -81,6 +82,17 @@ export default {
page: 1, page: 1,
perPage: 25, perPage: 25,
heartBeatList: [], heartBeatList: [],
paginationConfig: {
texts:{
count:`${this.$t("Showing {from} to {to} of {count} records")}|{count} ${this.$t("records")}|${this.$t("One record")}`,
first:this.$t("First"),
last:this.$t("Last"),
nextPage:'>',
nextChunk:'>>',
prevPage:'<',
prevChunk:'<<'
}
}
} }
}, },
computed: { computed: {

View file

@ -181,6 +181,7 @@
v-model="page" v-model="page"
:records="importantHeartBeatList.length" :records="importantHeartBeatList.length"
:per-page="perPage" :per-page="perPage"
:options="paginationConfig"
/> />
</div> </div>
</div> </div>
@ -237,6 +238,17 @@ export default {
heartBeatList: [], heartBeatList: [],
toggleCertInfoBox: false, toggleCertInfoBox: false,
showPingChartBox: true, showPingChartBox: true,
paginationConfig: {
texts:{
count:`${this.$t("Showing {from} to {to} of {count} records")}|{count} ${this.$t("records")}|${this.$t("One record")}`,
first:this.$t("First"),
last:this.$t("Last"),
nextPage:'>',
nextChunk:'>>',
prevPage:'<',
prevChunk:'<<'
}
}
} }
}, },
computed: { computed: {

View file

@ -226,7 +226,7 @@
{{ $t("Setup Notification") }} {{ $t("Setup Notification") }}
</button> </button>
<h2 class="mt-5">Info</h2> <h2 class="mt-5">{{ $t("Info") }}</h2>
{{ $t("Version") }}: {{ $root.info.version }} <br /> {{ $t("Version") }}: {{ $root.info.version }} <br />
<a href="https://github.com/louislam/uptime-kuma/releases" target="_blank" rel="noopener">{{ $t("Check Update On GitHub") }}</a> <a href="https://github.com/louislam/uptime-kuma/releases" target="_blank" rel="noopener">{{ $t("Check Update On GitHub") }}</a>
@ -316,6 +316,12 @@
<p>Пожалуйста, используйте с осторожностью.</p> <p>Пожалуйста, используйте с осторожностью.</p>
</template> </template>
<template v-else-if="$i18n.locale === 'fa' ">
<p>آیا مطمئن هستید که میخواهید <strong>احراز هویت را غیر فعال کنید</strong>?</p>
<p>این ویژگی برای کسانی است که <strong> لایه امنیتی شخص ثالث دیگر بر روی این آدرس فعال کردهاند</strong>، مانند Cloudflare Access.</p>
<p>لطفا از این امکان با دقت استفاده کنید.</p>
</template>
<template v-else-if="$i18n.locale === 'bg-BG' "> <template v-else-if="$i18n.locale === 'bg-BG' ">
<p>Сигурни ли сте, че желаете да <strong>изключите удостоверяването</strong>?</p> <p>Сигурни ли сте, че желаете да <strong>изключите удостоверяването</strong>?</p>
<p>Използва се в случаите, когато <strong>има настроен алтернативен метод за удостоверяване</strong> преди Uptime Kuma, например Cloudflare Access.</p> <p>Използва се в случаите, когато <strong>има настроен алтернативен метод за удостоверяване</strong> преди Uptime Kuma, например Cloudflare Access.</p>
@ -350,8 +356,9 @@ import TwoFADialog from "../components/TwoFADialog.vue";
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(timezone); dayjs.extend(timezone);
import { timezoneList } from "../util-frontend"; import { timezoneList, setPageLocale } from "../util-frontend";
import { useToast } from "vue-toastification"; import { useToast } from "vue-toastification";
const toast = useToast(); const toast = useToast();
export default { export default {
@ -387,6 +394,7 @@ export default {
"$i18n.locale"() { "$i18n.locale"() {
localStorage.locale = this.$i18n.locale; localStorage.locale = this.$i18n.locale;
setPageLocale()
}, },
}, },

View file

@ -197,7 +197,7 @@
</div> </div>
<footer class="mt-5 mb-4"> <footer class="mt-5 mb-4">
Powered by <a target="_blank" href="https://github.com/louislam/uptime-kuma">Uptime Kuma</a> {{ $t("Powered By") }} <a target="_blank" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" )}}</a>
</footer> </footer>
</div> </div>
</template> </template>

View file

@ -2,6 +2,7 @@ import dayjs from "dayjs";
import timezone from "dayjs/plugin/timezone"; import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc"; import utc from "dayjs/plugin/utc";
import timezones from "timezones-list"; import timezones from "timezones-list";
import { localeDirection, currentLocale } from "./i18n";
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(timezone); dayjs.extend(timezone);
@ -48,3 +49,9 @@ export function timezoneList() {
return result; return result;
} }
export function setPageLocale() {
const html = document.documentElement
html.setAttribute('lang', currentLocale() )
html.setAttribute('dir', localeDirection() )
}

View file

@ -2,6 +2,9 @@ import legacy from "@vitejs/plugin-legacy"
import vue from "@vitejs/plugin-vue" import vue from "@vitejs/plugin-vue"
import { defineConfig } from "vite" import { defineConfig } from "vite"
const postCssScss = require("postcss-scss")
const postcssRTLCSS = require('postcss-rtlcss');
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
@ -10,5 +13,12 @@ export default defineConfig({
targets: ["ie > 11"], targets: ["ie > 11"],
additionalLegacyPolyfills: ["regenerator-runtime/runtime"] additionalLegacyPolyfills: ["regenerator-runtime/runtime"]
}) })
] ],
css: {
postcss: {
"parser": postCssScss,
"map": false,
"plugins": [postcssRTLCSS]
}
},
}) })