feat: Add website Translation based on user browser language

This commit is contained in:
Kentai Radiquum 2024-12-06 21:23:37 +05:00
parent a8dea5ee51
commit 742fb28189
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
4 changed files with 244 additions and 192 deletions

68
static/i18n/i18n.js Normal file
View file

@ -0,0 +1,68 @@
const linkRegexFull =
/\|% LINK='[.,#?=&a-zA-Z_:_\/]*' %\|[.,a-zA-Zа-яА-Я-!_ ]*\|% ENDLINK %\|/gim;
const linkRegexFullNonGlobal =
/\|% LINK='[.,#?=&a-zA-Z_:_\/]*' %\|[.,a-zA-Zа-яА-Я-!_ ]*\|% ENDLINK %\|/im;
function parseLink(string) {
const links = [...string.match(linkRegexFull)];
const linkRegexStart = /\|% LINK='[.,#?=&a-zA-Z_:_\/]*' %\|/;
for (let i = 0; i < links.length; i++) {
let tmp = links[i];
const href = tmp
.match(linkRegexStart)[0]
.replace("|%", "")
.replace("%|", "")
.split("=")[1]
.trim();
let lnk = "";
lnk = tmp.replace(
linkRegexStart,
`<a class="text-bg-pink hover:underline" href=${href} ${href.startsWith("http") ? "target='_blank' referrerpolicy='origin'" : ""}>`
);
lnk = lnk.replace("|% ENDLINK %|", `</a>`);
string = string.replace(linkRegexFullNonGlobal, lnk);
}
return string;
}
const i18nTags = document.querySelectorAll("[data-i18n]");
const i18nStyles = document.querySelectorAll("[data-i18n-style]");
function changeLanguage(lang) {
let strings = {};
let styles = {};
if (lang == "ru") {
strings = i18n_ru;
styles = i18n_ru_style;
}
for (let i = 0; i < i18nTags.length; i++) {
const element = i18nTags[i];
const id = element.getAttribute("data-i18n");
if (!strings[id]) {
continue;
}
if (linkRegexFull.test(strings[id])) {
element.innerHTML = parseLink(strings[id]);
} else {
element.innerHTML = strings[id];
}
}
for (let i = 0; i < i18nStyles.length; i++) {
const element = i18nStyles[i];
const id = element.getAttribute("data-i18n-style");
if (!styles[id]) {
continue;
}
element.style.cssText = styles[id];
}
}
function detectAndChangeLanguage() {
const userLang = window.navigator.language;
if (userLang.startsWith("ru")) {
changeLanguage("ru");
}
}
detectAndChangeLanguage();

69
static/i18n/strings/ru.js Normal file
View file

@ -0,0 +1,69 @@
const i18n_ru = {
NAME: "КЕНТАЙ РАДИКУУМ",
PRONOUNCE: "Он",
SPECIES: "Красная Панда / Протоген",
// QUICK_BIO
QUICK_BIO_FURRY: "Фурри",
QUICK_BIO_CODER: "Программист",
QUICK_BIO_PHOTOGRAPHER: "Фотограф",
QUICK_BIO_ENTHUSIAST: "Селф-Хостинг Энтузиаст",
QUICK_BIO_LASTFM: "Сейчас слушает: ",
// BUTTONS
BTN_ABOUT_ME: "ОБО МНЕ",
BTN_OR: "или",
BTN_LINKS: "ССЫЛКИ",
// ABOUT ME
CARD_TITLE: "ОБО МНЕ",
CARD_TECH_ENTHUSIAST_TITLE: "Технический энтузиаст",
CARD_TECH_ENTHUSIAST_DESC:
"Мне нравится развиваться в области технологий, я увлечен разработкой программного обеспечения. Я люблю копаться в коде и изучать новое программное обеспечение, хотя железки меня тоже привлекают.",
CARD_PHOTOGRAPHER_TITLE: "Фотограф",
CARD_PHOTOGRAPHER_DESC:
"Я также увлекаюсь |% LINK='https://wah.su/photos' %|фотографией|% ENDLINK %| и с удовольствием делюсь своим прогрессом.",
CARD_SELFHOSTER_TITLE: "Самостоятельный хостинг",
CARD_SELFHOSTER_DESC:
"Я очень увлечен самостоятельным хостингом через мой проект |% LINK='https://home.wah.su' %|wah.su|% ENDLINK %|, который помогает мне погрузиться в управление серверами и хостинговыми платформами.",
CARD_MUSIC_TITLE: "Музыка",
CARD_MUSIC_DESC:
"Я слушаю много разной музыки, но в основном слушаю EDM / Happy Hardcore / Tech / Rock / Alternative. От таких исполнителей как: S3RL, Camellia, t+pazolite, BTMH, Saint Motel и других...",
CARD_SKILLS_TITLE: "Навыки",
CARD_SKILLS_FRONTEND: "Разработка фронт-енд",
CARD_SKILLS_BACKEND: "Разработка бэк-енд",
CARD_SKILLS_API: "API",
CARD_SKILLS_COLLAB: "Совместная работа",
CARD_SKILLS_DEPLOY: "Развёртывание",
CARD_READPANDA_TITLE: "Поклонник красных панд",
CARD_READPANDA_DESC:
"Я очень люблю красных панд и не могу насмотреться на них! Я собираю стикеры с красными пандами и делюсь ими в Telegram-канале |% LINK='https://t.me/red_panda_stickers' %|Red Panda Stickers|% ENDLINK %|. Кроме того, я собрал |% LINK='https://wahs.wah.su' %|коллекцию|% ENDLINK %| из более чем 3000 фотографий и видео с красными пандами.",
CARD_CONTACT_TITLE: "Связаться",
CARD_CONTACT_DESC:
"Не стесняйтесь связаться со мной в любое время! Способы связаться со мной через мессенджеры доступны в разделе |% LINK='#links' %|ссылок!|% ENDLINK %|.",
LNK_TITLE: "ССЫЛКИ",
LNK_PHOTO_HEADER: "ФОТОГРАФИИ",
LNK_PHOTO_PIXEY: "Смотри фото как в инстаграме",
LNK_PHOTO_INSTAFOPS: "Более фурри фото",
LNK_PHOTO_IMMICH: "Смотри фото как в Гугл Фото",
LNK_ARTS_HEADER: "АРТЫ",
LNK_SOCIALS_HEADER: "СОЦ. СЕТИ",
LNK_PROJECTS_HEADER: "ПРОЕКТЫ",
LNK_PROJECTS_ANIX:
"Неофициальный клиент для android приложения Anixart сделанный с помощью Next.js",
LNK_PROJECTS_TGP: "Телеграм бот для использования ТГ как гугл фото",
LNK_PROJECTS_WG: "Генератор слов вдохновлённый @tsoding",
LNK_PROJECTS_FADL: "Форк оригинального проекта для добавления новых функций",
LNK_PROJECTS_GITHUB: "Посмотреть мои другие репозитории",
LNK_PROJECTS_WAHSU: "Мой проект по селф-хосту",
LNK_CONTACT_HEADER: "СВЯЗАТЬСЯ",
LNK_FRIEND_HEADER: "ДРУЗЬЯ И КОЛЛЕКЦИИ",
LNK_COLLECTION_RPS: "ТГК для стикеров с красными пандами",
LNK_COLLECTION_RPI: "3000+ Фото и видео с красными пандами",
LNK_FRIEND_BLEP: "ВК Группа классного фотографа",
LNK_FRIEND_ITC: "GitHub профиль другого фурри-кодера",
};
const i18n_ru_style = {
CARD_SKILLS_STYLE: "--sm--mt:54px; --lg--mt:40px;",
};

View file

@ -698,22 +698,6 @@ video {
margin-top: 0.25rem;
}
.-ml-4 {
margin-left: -1rem;
}
.-mt-8 {
margin-top: -2rem;
}
.-mt-6 {
margin-top: -1.5rem;
}
.-ml-2 {
margin-left: -0.5rem;
}
.block {
display: block;
}
@ -762,11 +746,6 @@ video {
height: 100%;
}
.h-fit {
height: -moz-fit-content;
height: fit-content;
}
.max-h-\[182px\] {
max-height: 182px;
}
@ -825,21 +804,6 @@ video {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.translate-y-full {
--tw-translate-y: 100%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.translate-y-\[50\%\] {
--tw-translate-y: 50%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.translate-y-\[80\%\] {
--tw-translate-y: 80%;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
@keyframes bounce {
0%, 100% {
transform: translateY(-25%);
@ -1021,6 +985,11 @@ video {
background-color: rgb(245 245 245 / var(--tw-bg-opacity));
}
.bg-\[\#ffeb3c\] {
--tw-bg-opacity: 1;
background-color: rgb(255 235 60 / var(--tw-bg-opacity));
}
.bg-bg-black {
--tw-bg-opacity: 1;
background-color: rgb(18 27 44 / var(--tw-bg-opacity));
@ -1076,14 +1045,8 @@ video {
background-color: rgb(234 179 8 / var(--tw-bg-opacity));
}
.bg-\[\#ffeb3c\] {
--tw-bg-opacity: 1;
background-color: rgb(255 235 60 / var(--tw-bg-opacity));
}
.bg-slate-500 {
--tw-bg-opacity: 1;
background-color: rgb(100 116 139 / var(--tw-bg-opacity));
.bg-opacity-20 {
--tw-bg-opacity: 0.2;
}
.bg-opacity-40 {
@ -1094,14 +1057,6 @@ video {
--tw-bg-opacity: 0.5;
}
.bg-opacity-10 {
--tw-bg-opacity: 0.1;
}
.bg-opacity-20 {
--tw-bg-opacity: 0.2;
}
.object-contain {
-o-object-fit: contain;
object-fit: contain;
@ -1166,10 +1121,6 @@ video {
text-align: right;
}
.align-text-bottom {
vertical-align: text-bottom;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
@ -1200,11 +1151,6 @@ video {
line-height: 1.75rem;
}
.text-6xl {
font-size: 3.75rem;
line-height: 1;
}
.font-bold {
font-weight: 700;
}
@ -1236,72 +1182,19 @@ video {
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.text-gray-500 {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.underline {
text-decoration-line: underline;
}
.mix-blend-multiply {
mix-blend-mode: multiply;
}
.mix-blend-exclusion {
mix-blend-mode: exclusion;
}
.shadow {
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow-md {
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow-inner {
--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow-black {
--tw-shadow-color: #000;
--tw-shadow: var(--tw-shadow-colored);
}
.brightness-50 {
--tw-brightness: brightness(.5);
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.invert {
--tw-invert: invert(100%);
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.backdrop-blur-lg {
--tw-backdrop-blur: blur(16px);
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
}
.backdrop-invert {
--tw-backdrop-invert: invert(100%);
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
}
.transition-\[border-color\] {
transition-property: border-color;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
@ -1422,8 +1315,8 @@ body {
top: -6rem;
}
.sm\:-mt-\[86px\] {
margin-top: -86px;
.sm\:-mt-\[var\(--sm--mt\)\] {
margin-top: calc(var(--sm--mt) * -1);
}
.sm\:mt-0 {
@ -1553,8 +1446,8 @@ body {
}
@media (min-width: 1024px) {
.lg\:-mt-\[60px\] {
margin-top: -60px;
.lg\:-mt-\[var\(--lg--mt\)\] {
margin-top: calc(var(--lg--mt) * -1);
}
.lg\:mt-28 {