feat: translations support

This commit is contained in:
Markos Gogoulos 2024-10-04 13:17:40 +03:00 committed by GitHub
parent ef4067cbdd
commit 4992cc425c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
84 changed files with 2303 additions and 161 deletions

15
Makefile Normal file
View File

@ -0,0 +1,15 @@
.PHONY: admin-shell build-frontend
admin-shell:
@container_id=$$(docker-compose ps -q web); \
if [ -z "$$container_id" ]; then \
echo "Web container not found"; \
exit 1; \
else \
docker exec -it $$container_id /bin/bash; \
fi
build-frontend:
docker-compose -f docker-compose-dev.yaml exec frontend npm run dist
cp -r frontend/dist/static/* static/
docker-compose -f docker-compose-dev.yaml restart web

View File

@ -41,23 +41,20 @@ A demo is available at https://demo.mediacms.io
- **Scalable transcoding**: transcoding through priorities. Experimental support for remote workers
- **Chunked file uploads**: for pausable/resumable upload of content
- **REST API**: Documented through Swagger
- **Translation**: Most of the CMS is translated to a number of languages
## Example cases
- **Schools, education.** Administrators and editors keep what content will be published, students are not distracted with advertisements and irrelevant content, plus they have the ability to select either to stream or download content.
- **Organization sensitive content.** In cases where content is sensitive and cannot be uploaded to external sites.
- **Build a great community.** MediaCMS can be customized (URLs, logos, fonts, aesthetics) so that you create a highly customized video portal for your community!
- **Personal portal.** Organize, categorize and host your content the way you prefer.
## Philosophy
We believe there's a need for quality open source web applications that can be used to build community portals and support collaboration.
We have three goals for MediaCMS: a) deliver all functionality one would expect from a modern system, b) allow for easy installation and maintenance, c) allow easy customization and addition of features.
@ -80,17 +77,12 @@ For a small to medium installation, with a few hours of video uploaded daily, an
In terms of disk space, think of what the needs will be. A general rule is to multiply by three the size of the expected uploaded videos (since the system keeps original versions, encoded versions plus HLS), so if you receive 1G of videos daily and maintain all of them, you should consider a 1T disk across a year (1G * 3 * 365).
## Releases
Visit [Releases Page](https://github.com/mediacms-io/mediacms/releases) for detailed Changelog
## Installation / Maintanance
There are two ways to run MediaCMS, through Docker Compose and through installing it on a server via an automation script that installs and configures all needed services. Find the related pages:
* [Single Server](docs/admins_docs.md#2-server-installation) page
* [Docker Compose](docs/admins_docs.md#3-docker-installation) page
- [Single Server](docs/admins_docs.md#2-server-installation) page
- [Docker Compose](docs/admins_docs.md#3-docker-installation) page
A complete guide can be found on the blog post [How to self-host and share your videos in 2021](https://medium.com/@MediaCMS.io/how-to-self-host-and-share-your-videos-in-2021-14067e3b291b).
@ -119,7 +111,7 @@ This software uses the following list of awesome technologies: Python, Django, D
- **Cinemata** non-profit media, technology and culture organization - https://cinemata.org
- **Critical Commons** public media archive and fair use advocacy network - https://criticalcommons.org
- **American Association of Gynecologic Laparoscopists** - https://surgeryu.aagl.org/
- **American Association of Gynecologic Laparoscopists** - https://surgeryu.org/
## How to contribute

View File

@ -34,6 +34,7 @@ MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
"django.middleware.locale.LocaleMiddleware",
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',

View File

@ -1,6 +1,7 @@
import os
from celery.schedules import crontab
from django.utils.translation import gettext_lazy as _
DEBUG = False
@ -311,6 +312,7 @@ INSTALLED_APPS = [
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
@ -507,3 +509,25 @@ try:
from .dev_settings import * # noqa
except ImportError:
pass
LANGUAGES = [
('ar', _('Arabic')),
('bn', _('Bengali')),
('nl', _('Dutch')),
('en', _('English')),
('fr', _('French')),
('de', _('German')),
('hi', _('Hindi')),
('id', _('Indonesian')),
('ja', _('Japanese')),
('ko', _('Korean')),
('pt', _('Portuguese')),
('ru', _('Russian')),
('zh-hans', _('Simplified Chinese')),
('es', _('Spanish')),
('tr', _('Turkish')),
('el', _('Greek')),
('ur', _('Urdu')),
]
LANGUAGE_CODE = 'en' # default language

View File

@ -13,6 +13,7 @@ schema_view = get_schema_view(
permission_classes=(AllowAny,),
)
# refactor seriously
urlpatterns = [
re_path(r"^__debug__/", include(debug_toolbar.urls)),

View File

@ -20,6 +20,7 @@
- [17. Cookie consent code](#17-cookie-consent-code)
- [18. Disable encoding and show only original file](#18-disable-encoding-and-show-only-original-file)
- [19. Rounded corners on videos](#19-rounded-corners)
- [20. Translations](#20-translations)
## 1. Welcome
This page is created for MediaCMS administrators that are responsible for setting up the software, maintaining it and making modifications.
@ -801,3 +802,41 @@ frontend/src/static/js/components/list-item/Item.scss
frontend/src/static/js/components/media-page/MediaPage.scss
```
you now have to re-run the frontend build in order to see the changes (check docs/dev_exp.md)
## 20. Translations
### 20.1 Set a default language
By default MediaCMS is available in a number of languages. To set the default language, edit `settings.py` and set LANGUAGE_CODE to the code of one of the languages.
### 20.2 Remove existing languages
To limit the number of languages that are shown as available, remove them from the LANGUAGES list in `settings.py` or comment them. Only what is there is shown.
### 20.3 Improve existing translation
To make improvements in existing translated content, in a language that is already translated, check the language by the code name in `files/frontend-translations/` and edit the corresponding file.
### 20.4 Add more content to existing translation
Not all text is translated, so at any time you may find strings missing that need to be added to the translation. The idea here is that
a) you made the text as translatable, in the code
b) you add the translated string
For a), you have to see if the string to be translated lives in the frontend directory (React app) or on the Django templates. There are examples for both.
1. the Django templates, which is found in templates/ dir. Have a look on `templates/cms/about.html` to see an example of how it is done
2. the frontend code (React), have a look how `translateString` is used in `frontend`
After the string is marked as translatable, add the string to `files/frontend-translations/en.py` first, and then run
```
python manage.py process_translations
```
In order to populate the string in all the languages. NO PR will be accepted if this procedure is not followed. You don't have to translate the string to all supported languages, but the command has to run and populate the existing dictionaries with the new strings for all languages. This ensures that there is no missing string to be translated in any language.
After this command is run, translate the string to the language you want. If the string to be translated lives in Django templates, you don't have to re-build the frontend. If the change lives in the frontend, you will have to re-build in order to see the changes. The Makefile command `make build-frontend` can help with this.
### 20.5 Add a new language and translate
To add a new language: add the language in settings.py, then add the file in `files/frontend-translations/`. Make sure you copy the initial strings by copying `files/frontend-translations/en.py` to it.

View File

@ -34,6 +34,14 @@ Check it on http://localhost:8088/
### How to develop in Django
Django starts at http://localhost and is reloading automatically. Making any change to the python code should refresh Django.
If Django breaks due to an error (eg SyntaxError, while editing the code), you might have to restart it
```
docker-compose -f docker-compose-dev.yaml restart web
```
### How to develop in React
React is started on http://localhost:8088/ , code is located in frontend/ , so making changes there should have instant effect on the page. Keep in mind that React is loading data from Django, and that it has to be built so that Django can serve it.
@ -57,4 +65,25 @@ In order to make changes to React code, edit code on frontend/src and check it's
3. Build frontend with `docker-compose -f docker-compose-dev.yaml exec frontend npm run dist`
4. Copy static files to Django static folder with`cp -r frontend/dist/static/* static/`
5. Restart Django - `docker-compose -f docker-compose-dev.yaml restart web` so that it uses the new static files
6. Commit the changes
6. Commit the changes
### Helper commands
There is ongoing effort to provide helper commands, check the Makefile for what it supports. Eg
Bash into the web container:
```
user@user:~/mediacms$ make admin-shell
root@ca8c1096726b:/home/mediacms.io/mediacms# ./manage.py shell
```
Build the frontend:
```
user@user:~/mediacms$ make build-frontend
docker-compose -f docker-compose-dev.yaml exec frontend npm run dist
> mediacms-frontend@0.9.1 dist /home/mediacms.io/mediacms/frontend
> mediacms-scripts rimraf ./dist && mediacms-scripts build --config=./config/mediacms.config.js --env=dist
...
```

View File

@ -1,15 +1,6 @@
from django.contrib import admin
from .models import (
Category,
Comment,
EncodeProfile,
Encoding,
Language,
Media,
Subtitle,
Tag,
)
from .models import Category, Comment, EncodeProfile, Encoding, Language, Media, Subtitle, Tag
class CommentAdmin(admin.ModelAdmin):

View File

@ -1,5 +1,6 @@
from django.conf import settings
from .frontend_translations import get_translation, get_translation_strings
from .methods import is_mediacms_editor, is_mediacms_manager
@ -31,4 +32,7 @@ def stuff(request):
ret["ALLOW_RATINGS_CONFIRMED_EMAIL_ONLY"] = settings.ALLOW_RATINGS_CONFIRMED_EMAIL_ONLY
ret["VIDEO_PLAYER_FEATURED_VIDEO_ON_INDEX_PAGE"] = settings.VIDEO_PLAYER_FEATURED_VIDEO_ON_INDEX_PAGE
ret["RSS_URL"] = "/rss"
ret["TRANSLATION"] = get_translation(request.LANGUAGE_CODE)
ret["REPLACEMENTS"] = get_translation_strings(request.LANGUAGE_CODE)
return ret

View File

@ -0,0 +1,61 @@
import importlib
import os
from django.conf import settings
current_dir = os.path.dirname(os.path.abspath(__file__))
files = os.listdir(current_dir)
translation_strings = {}
replacement_strings = {}
def check_language_code(language_code):
# helper function
if language_code not in [pair[0] for pair in settings.LANGUAGES]:
return False
if language_code in ['en', 'en-us', 'en-gb']:
return False
return True
for translation_file in files:
# the language code is zh-hans but the file is zh_hans.py
language_code_file = translation_file.split('.')[0]
language_code = language_code_file.replace('_', '-')
if not check_language_code(language_code):
continue
module_name = f"files.frontend_translations.{language_code_file}"
tr_module = importlib.import_module(module_name)
translation_strings[language_code] = tr_module.translation_strings
replacement_strings[language_code] = tr_module.replacement_strings
def get_translation(language_code):
# get list of translations per language
if not check_language_code(language_code):
return {}
translation = translation_strings[language_code]
return translation
def get_translation_strings(language_code):
# get list of replacement strings per language
if not check_language_code(language_code):
return {}
translation = replacement_strings[language_code]
return translation
def translate_string(language_code, string):
# translate a string to the given language
if not check_language_code(language_code):
return string
return translation_strings[language_code].get(string, string)

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "حول",
"AUTOPLAY": "تشغيل تلقائي",
"About": "حول",
"Add a ": "أضف ",
"COMMENT": "تعليق",
"Categories": "الفئات",
"Category": "الفئة",
"Change Language": "تغيير اللغة",
"Change password": "تغيير كلمة المرور",
"Comment": "تعليق",
"Comments": "تعليقات",
"Comments are disabled": "التعليقات معطلة",
"Contact": "اتصل",
"DELETE MEDIA": "حذف الوسائط",
"DOWNLOAD": "تحميل",
"EDIT MEDIA": "تعديل الوسائط",
"EDIT PROFILE": "تعديل الملف الشخصي",
"EDIT SUBTITLE": "تعديل الترجمة",
"Edit media": "تعديل الوسائط",
"Edit profile": "تعديل الملف الشخصي",
"Edit subtitle": "تعديل الترجمة",
"Featured": "مميز",
"Go": "اذهب",
"History": "التاريخ",
"Home": "الرئيسية",
"Language": "اللغة",
"Latest": "الأحدث",
"Liked media": "الوسائط المفضلة",
"Manage comments": "إدارة التعليقات",
"Manage media": "إدارة الوسائط",
"Manage users": "إدارة المستخدمين",
"Media": "وسائط",
"Media was edited": "تم تعديل الوسائط",
"Members": "الأعضاء",
"My media": "وسائطي",
"My playlists": "قوائم التشغيل الخاصة بي",
"No": "لا",
"No comment yet": "لا يوجد تعليق بعد",
"No comments yet": "لا توجد تعليقات بعد",
"No results for": "لا توجد نتائج لـ",
"PLAYLISTS": "قوائم التشغيل",
"Playlists": "قوائم التشغيل",
"Powered by": "مدعوم من",
"Published on": "نشر في",
"Recommended": "موصى به",
"Register": "تسجيل",
"SAVE": "حفظ",
"SEARCH": "بحث",
"SHARE": "مشاركة",
"SHOW MORE": "عرض المزيد",
"SUBMIT": "إرسال",
"Search": "بحث",
"Select": "اختر",
"Sign in": "تسجيل الدخول",
"Sign out": "تسجيل الخروج",
"Subtitle was added": "تمت إضافة الترجمة",
"Tags": "العلامات",
"Terms": "الشروط",
"UPLOAD": "رفع",
"Up next": "التالي",
"Upload": "رفع",
"Upload media": "رفع الوسائط",
"Uploads": "التحميلات",
"VIEW ALL": "عرض الكل",
"View all": "عرض الكل",
"comment": "تعليق",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "هو نظام إدارة محتوى فيديو ووسائط مفتوح المصدر وحديث ومتكامل. تم تطويره لتلبية احتياجات المنصات الويب الحديثة لمشاهدة ومشاركة الوسائط",
"media in category": "وسائط في الفئة",
"media in tag": "وسائط في العلامة",
"view": "عرض",
"views": "مشاهدات",
"yet": "بعد",
}
replacement_strings = {
"Apr": "أبريل",
"Aug": "أغسطس",
"Dec": "ديسمبر",
"Feb": "فبراير",
"Jan": "يناير",
"Jul": "يوليو",
"Jun": "يونيو",
"Mar": "مارس",
"May": "مايو",
"Nov": "نوفمبر",
"Oct": "أكتوبر",
"Sep": "سبتمبر",
"day ago": "منذ يوم",
"days ago": "منذ أيام",
"hour ago": "منذ ساعة",
"hours ago": "منذ ساعات",
"just now": "الآن",
"minute ago": "منذ دقيقة",
"minutes ago": "منذ دقائق",
"month ago": "منذ شهر",
"months ago": "منذ شهور",
"second ago": "منذ ثانية",
"seconds ago": "منذ ثوان",
"week ago": "منذ أسبوع",
"weeks ago": "منذ أسابيع",
"year ago": "منذ سنة",
"years ago": "منذ سنوات",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "সম্পর্কে",
"AUTOPLAY": "স্বয়ংক্রিয় প্লে",
"About": "সম্পর্কে",
"Add a ": "যোগ করুন",
"COMMENT": "মন্তব্য",
"Categories": "বিভাগসমূহ",
"Category": "বিভাগ",
"Change Language": "ভাষা পরিবর্তন করুন",
"Change password": "পাসওয়ার্ড পরিবর্তন করুন",
"Comment": "মন্তব্য",
"Comments": "মন্তব্যসমূহ",
"Comments are disabled": "মন্তব্য নিষ্ক্রিয় করা হয়েছে",
"Contact": "যোগাযোগ",
"DELETE MEDIA": "মিডিয়া মুছুন",
"DOWNLOAD": "ডাউনলোড",
"EDIT MEDIA": "মিডিয়া সম্পাদনা করুন",
"EDIT PROFILE": "প্রোফাইল সম্পাদনা করুন",
"EDIT SUBTITLE": "সাবটাইটেল সম্পাদনা করুন",
"Edit media": "মিডিয়া সম্পাদনা করুন",
"Edit profile": "প্রোফাইল সম্পাদনা করুন",
"Edit subtitle": "সাবটাইটেল সম্পাদনা করুন",
"Featured": "বৈশিষ্ট্যযুক্ত",
"Go": "যাও",
"History": "ইতিহাস",
"Home": "বাড়ি",
"Language": "ভাষা",
"Latest": "সর্বশেষ",
"Liked media": "পছন্দের মিডিয়া",
"Manage comments": "মন্তব্য পরিচালনা করুন",
"Manage media": "মিডিয়া পরিচালনা করুন",
"Manage users": "ব্যবহারকারীদের পরিচালনা করুন",
"Media": "মিডিয়া",
"Media was edited": "মিডিয়া সম্পাদিত হয়েছে",
"Members": "সদস্যরা",
"My media": "আমার মিডিয়া",
"My playlists": "আমার প্লেলিস্ট",
"No": "না",
"No comment yet": "এখনও কোন মন্তব্য নেই",
"No comments yet": "এখনও কোন মন্তব্য নেই",
"No results for": "এর জন্য কোন ফলাফল নেই",
"PLAYLISTS": "প্লেলিস্ট",
"Playlists": "প্লেলিস্ট",
"Powered by": "দ্বারা চালিত",
"Published on": "প্রকাশিত",
"Recommended": "প্রস্তাবিত",
"Register": "নিবন্ধন করুন",
"SAVE": "সংরক্ষণ করুন",
"SEARCH": "অনুসন্ধান",
"SHARE": "শেয়ার করুন",
"SHOW MORE": "আরও দেখুন",
"SUBMIT": "জমা দিন",
"Search": "অনুসন্ধান",
"Select": "নির্বাচন করুন",
"Sign in": "সাইন ইন করুন",
"Sign out": "সাইন আউট করুন",
"Subtitle was added": "সাবটাইটেল যোগ করা হয়েছে",
"Tags": "ট্যাগ",
"Terms": "শর্তাবলী",
"UPLOAD": "আপলোড করুন",
"Up next": "পরবর্তী",
"Upload": "আপলোড করুন",
"Upload media": "মিডিয়া আপলোড করুন",
"Uploads": "আপলোডসমূহ",
"VIEW ALL": "সব দেখুন",
"View all": "সব দেখুন",
"comment": "মন্তব্য",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "একটি আধুনিক, সম্পূর্ণ বৈশিষ্ট্যযুক্ত ওপেন সোর্স ভিডিও এবং মিডিয়া CMS। এটি আধুনিক ওয়েব প্ল্যাটফর্মের জন্য মিডিয়া দেখার এবং শেয়ার করার প্রয়োজন মেটাতে তৈরি করা হয়েছে",
"media in category": "বিভাগে মিডিয়া",
"media in tag": "ট্যাগে মিডিয়া",
"view": "দেখুন",
"views": "দেখা হয়েছে",
"yet": "এখনও",
}
replacement_strings = {
"Apr": "এপ্রিল",
"Aug": "আগস্ট",
"Dec": "ডিসেম্বর",
"Feb": "ফেব্রু",
"Jan": "জানু",
"Jul": "জুলাই",
"Jun": "জুন",
"Mar": "মার্চ",
"May": "মে",
"Nov": "নভেম্বর",
"Oct": "অক্টোবর",
"Sep": "সেপ্টেম্বর",
"day ago": "দিন আগে",
"days ago": "দিন আগে",
"hour ago": "ঘণ্টা আগে",
"hours ago": "ঘণ্টা আগে",
"just now": "এখনই",
"minute ago": "মিনিট আগে",
"minutes ago": "মিনিট আগে",
"month ago": "মাস আগে",
"months ago": "মাস আগে",
"second ago": "সেকেন্ড আগে",
"seconds ago": "সেকেন্ড আগে",
"week ago": "সপ্তাহ আগে",
"weeks ago": "সপ্তাহ আগে",
"year ago": "বছর আগে",
"years ago": "বছর আগে",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "Über",
"AUTOPLAY": "Automatische Wiedergabe",
"About": "Über",
"Add a ": "Hinzufügen eines ",
"COMMENT": "KOMMENTAR",
"Categories": "Kategorien",
"Category": "Kategorie",
"Change Language": "Sprache ändern",
"Change password": "Passwort ändern",
"Comment": "Kommentar",
"Comments": "Kommentare",
"Comments are disabled": "Kommentare sind deaktiviert",
"Contact": "Kontakt",
"DELETE MEDIA": "MEDIEN LÖSCHEN",
"DOWNLOAD": "HERUNTERLADEN",
"EDIT MEDIA": "MEDIEN BEARBEITEN",
"EDIT PROFILE": "PROFIL BEARBEITEN",
"EDIT SUBTITLE": "UNTERTITEL BEARBEITEN",
"Edit media": "Medien bearbeiten",
"Edit profile": "Profil bearbeiten",
"Edit subtitle": "Untertitel bearbeiten",
"Featured": "Empfohlen",
"Go": "Los",
"History": "Verlauf",
"Home": "Startseite",
"Language": "Sprache",
"Latest": "Neueste",
"Liked media": "Beliebte Medien",
"Manage comments": "Kommentare verwalten",
"Manage media": "Medien verwalten",
"Manage users": "Benutzer verwalten",
"Media": "Medien",
"Media was edited": "Medien wurden bearbeitet",
"Members": "Mitglieder",
"My media": "Meine Medien",
"My playlists": "Meine Playlists",
"No": "Nein",
"No comment yet": "Noch kein Kommentar",
"No comments yet": "Noch keine Kommentare",
"No results for": "Keine Ergebnisse für",
"PLAYLISTS": "PLAYLISTS",
"Playlists": "Playlists",
"Powered by": "Bereitgestellt von",
"Published on": "Veröffentlicht am",
"Recommended": "Empfohlen",
"Register": "Registrieren",
"SAVE": "SPEICHERN",
"SEARCH": "SUCHE",
"SHARE": "TEILEN",
"SHOW MORE": "MEHR ANZEIGEN",
"SUBMIT": "ABSENDEN",
"Search": "Suche",
"Select": "Auswählen",
"Sign in": "Anmelden",
"Sign out": "Abmelden",
"Subtitle was added": "Untertitel wurde hinzugefügt",
"Tags": "Tags",
"Terms": "Bedingungen",
"UPLOAD": "HOCHLADEN",
"Up next": "Als nächstes",
"Upload": "Hochladen",
"Upload media": "Medien hochladen",
"Uploads": "Uploads",
"VIEW ALL": "ALLE ANZEIGEN",
"View all": "Alle anzeigen",
"comment": "Kommentar",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "ist ein modernes, voll ausgestattetes Open-Source-Video- und Medien-CMS. Es wurde entwickelt, um den Anforderungen moderner Webplattformen für das Ansehen und Teilen von Medien gerecht zu werden",
"media in category": "Medien in Kategorie",
"media in tag": "Medien in Tag",
"view": "Ansicht",
"views": "Ansichten",
"yet": "noch",
}
replacement_strings = {
"Apr": "Apr",
"Aug": "Aug",
"Dec": "Dez",
"Feb": "Feb",
"Jan": "Jan",
"Jul": "Jul",
"Jun": "Jun",
"Mar": "Mär",
"May": "Mai",
"Nov": "Nov",
"Oct": "Okt",
"Sep": "Sep",
"day ago": "vor einem Tag",
"days ago": "vor Tagen",
"hour ago": "vor einer Stunde",
"hours ago": "vor Stunden",
"just now": "gerade eben",
"minute ago": "vor einer Minute",
"minutes ago": "vor Minuten",
"month ago": "vor einem Monat",
"months ago": "vor Monaten",
"second ago": "vor einer Sekunde",
"seconds ago": "vor Sekunden",
"week ago": "vor einer Woche",
"weeks ago": "vor Wochen",
"year ago": "vor einem Jahr",
"years ago": "vor Jahren",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "ΣΧΕΤΙΚΑ",
"AUTOPLAY": "Αυτόματη αναπαραγωγή",
"About": "Σχετικά",
"Add a ": "Προσθέστε ένα ",
"COMMENT": "ΣΧΟΛΙΟ",
"Categories": "Κατηγορίες",
"Category": "Κατηγορία",
"Change Language": "Αλλαγή Γλώσσας",
"Change password": "Αλλαγή κωδικού",
"Comment": "Σχόλιο",
"Comments": "Σχόλια",
"Comments are disabled": "Τα σχόλια είναι απενεργοποιημένα",
"Contact": "Επικοινωνία",
"DELETE MEDIA": "ΔΙΑΓΡΑΦΗ ΑΡΧΕΙΟΥ",
"DOWNLOAD": "ΚΑΤΕΒΑΣΜΑ",
"EDIT MEDIA": "ΕΠΕΞΕΡΓΑΣΙΑ ΑΡΧΕΙΟΥ",
"EDIT PROFILE": "ΕΠΕΞΕΡΓΑΣΙΑ ΠΡΟΦΙΛ",
"EDIT SUBTITLE": "ΕΠΕΞΕΡΓΑΣΙΑ ΥΠΟΤΙΤΛΩΝ",
"Edit media": "Επεξεργασία αρχείου",
"Edit profile": "Επεξεργασία προφιλ",
"Edit subtitle": "Επεξεργασία υποτίτλων",
"Featured": "Επιλεγμένα",
"Go": "Πήγαινε",
"History": "Ιστορικό",
"Home": "Αρχική",
"Language": "Γλώσσα",
"Latest": "Πρόσφατα",
"Liked media": "Αγαπημένα",
"Manage comments": "Διαχείριση σχολίων",
"Manage media": "Διαχείριση αρχείων",
"Manage users": "Διαχείριση χρηστών",
"Media": "Αρχεία",
"Media was edited": "Το αρχείο επεξεργάστηκε",
"Members": "Μέλη",
"My media": "Τα αρχεία μου",
"My playlists": "Οι λίστες μου",
"No": "Όχι",
"No comment yet": "Δεν υπάρχει ακόμα σχόλιο",
"No comments yet": "Δεν υπάρχουν ακόμα σχόλια",
"No results for": "Δεν υπάρχουν αποτελέσματα για",
"PLAYLISTS": "ΛΙΣΤΕΣ",
"Playlists": "Λίστες",
"Powered by": "Υποστηρίζεται από το",
"Published on": "Δημοσιεύτηκε στις",
"Recommended": "Προτεινόμενα",
"Register": "Εγγραφή",
"SAVE": "ΑΠΟΘΗΚΕΥΣΗ",
"SEARCH": "ΑΝΑΖΗΤΗΣΗ",
"SHARE": "ΚΟΙΝΟΠΟΙΗΣΗ",
"SHOW MORE": "ΠΕΡΙΣΣΟΤΕΡΑ",
"SUBMIT": "ΥΠΟΒΟΛΗ",
"Search": "Αναζήτηση",
"Select": "Επιλογή",
"Sign in": "Σύνδεση",
"Sign out": "Αποσύνδεση",
"Subtitle was added": "Οι υπότιτλοι προστέθηκαν",
"Tags": "Ετικέτες",
"Terms": "Όροι",
"UPLOAD": "ΑΝΕΒΑΣΜΑ",
"Up next": "Επόμενο",
"Upload": "Ανέβασμα αρχείου",
"Upload media": "Ανέβασμα αρχείων",
"Uploads": "Ανεβάσματα",
"VIEW ALL": "ΔΕΣ ΤΑ ΟΛΑ",
"View all": "Δές τα όλα",
"comment": "σχόλιο",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "είναι ένα σύγχρονο, πλήρως λειτουργικό ανοιχτού κώδικα CMS βίντεο και πολυμέσων. Αναπτύχθηκε για να καλύψει τις ανάγκες των σύγχρονων πλατφορμών ιστού για την προβολή και την κοινοποίηση πολυμέσων",
"media in category": "αρχεία στην κατηγορία",
"media in tag": "αρχεία με ετικέτα",
"view": "προβολή",
"views": "προβολές",
"yet": "ακόμα",
}
replacement_strings = {
"Apr": "Απρ",
"Aug": "Αυγ",
"Dec": "Δεκ",
"Feb": "Φεβ",
"Jan": "Ιαν",
"Jul": "Ιουλ",
"Jun": "Ιουν",
"Mar": "Μαρ",
"May": "Μαϊ",
"Nov": "Νοε",
"Oct": "Οκτ",
"Sep": "Σεπτ",
"day ago": "μέρα πριν",
"days ago": "μέρες πριν",
"hour ago": "ώρα πριν",
"hours ago": "ώρες πριν",
"just now": "μόλις τώρα",
"minute ago": "λεπτό πριν",
"minutes ago": "λεπτά πριν",
"month ago": "μήνας πριν",
"months ago": "μήνες πριν",
"second ago": "δευτερόλεπτο πριν",
"seconds ago": "δευτερόλεπτα πριν",
"week ago": "εβδομάδα πριν",
"weeks ago": "εβδομάδες πριν",
"year ago": "χρόνος πριν",
"years ago": "χρόνια πριν",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "",
"AUTOPLAY": "",
"Add a ": "",
"COMMENT": "",
"Categories": "",
"Category": "",
"Change Language": "",
"Change password": "",
"About": "",
"Comment": "",
"Comments": "",
"Comments are disabled": "",
"Contact": "",
"DELETE MEDIA": "",
"DOWNLOAD": "",
"EDIT MEDIA": "",
"EDIT PROFILE": "",
"EDIT SUBTITLE": "",
"Edit media": "",
"Edit profile": "",
"Edit subtitle": "",
"Featured": "",
"Go": "",
"History": "",
"Home": "",
"Language": "",
"Latest": "",
"Liked media": "",
"Manage comments": "",
"Manage media": "",
"Manage users": "",
"Media": "",
"Media was edited": "",
"Members": "",
"My media": "",
"My playlists": "",
"No": "",
"No comment yet": "",
"No comments yet": "",
"No results for": "",
"PLAYLISTS": "",
"Playlists": "",
"Powered by": "",
"Published on": "",
"Recommended": "",
"Register": "",
"SAVE": "",
"SEARCH": "",
"SHARE": "",
"SHOW MORE": "",
"SUBMIT": "",
"Search": "",
"Select": "",
"Sign in": "",
"Sign out": "",
"Subtitle was added": "",
"Tags": "",
"Terms": "",
"UPLOAD": "",
"Up next": "",
"Upload": "",
"Upload media": "",
"Uploads": "",
"VIEW ALL": "",
"View all": "",
"comment": "",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "",
"media in category": "",
"media in tag": "",
"view": "",
"views": "",
"yet": "",
}
replacement_strings = {
"Apr": "",
"Aug": "",
"Dec": "",
"Feb": "",
"Jan": "",
"Jul": "",
"Jun": "",
"Mar": "",
"May": "",
"Nov": "",
"Oct": "",
"Sep": "",
"day ago": "",
"days ago": "",
"hour ago": "",
"hours ago": "",
"just now": "",
"minute ago": "",
"minutes ago": "",
"month ago": "",
"months ago": "",
"second ago": "",
"seconds ago": "",
"week ago": "",
"weeks ago": "",
"year ago": "",
"years ago": "",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "Acerca de",
"AUTOPLAY": "Reproducción automática",
"About": "Acerca de",
"Add a ": "Agregar un ",
"COMMENT": "COMENTARIO",
"Categories": "Categorías",
"Category": "Categoría",
"Change Language": "Cambiar idioma",
"Change password": "Cambiar contraseña",
"Comment": "Comentario",
"Comments": "Comentarios",
"Comments are disabled": "Los comentarios están deshabilitados",
"Contact": "Contacto",
"DELETE MEDIA": "ELIMINAR MEDIOS",
"DOWNLOAD": "DESCARGAR",
"EDIT MEDIA": "EDITAR MEDIOS",
"EDIT PROFILE": "EDITAR PERFIL",
"EDIT SUBTITLE": "EDITAR SUBTÍTULO",
"Edit media": "Editar medios",
"Edit profile": "Editar perfil",
"Edit subtitle": "Editar subtítulo",
"Featured": "Destacado",
"Go": "Ir",
"History": "Historial",
"Home": "Inicio",
"Language": "Idioma",
"Latest": "Último",
"Liked media": "Medios que me gustan",
"Manage comments": "Gestionar comentarios",
"Manage media": "Gestionar medios",
"Manage users": "Gestionar usuarios",
"Media": "Medios",
"Media was edited": "El medio fue editado",
"Members": "Miembros",
"My media": "Mis medios",
"My playlists": "Mis listas de reproducción",
"No": "No",
"No comment yet": "Aún no hay comentarios",
"No comments yet": "Aún no hay comentarios",
"No results for": "No hay resultados para",
"PLAYLISTS": "LISTAS DE REPRODUCCIÓN",
"Playlists": "Listas de reproducción",
"Powered by": "Desarrollado por",
"Published on": "Publicado en",
"Recommended": "Recomendado",
"Register": "Registrarse",
"SAVE": "GUARDAR",
"SEARCH": "BUSCAR",
"SHARE": "COMPARTIR",
"SHOW MORE": "MOSTRAR MÁS",
"SUBMIT": "ENVIAR",
"Search": "Buscar",
"Select": "Seleccionar",
"Sign in": "Iniciar sesión",
"Sign out": "Cerrar sesión",
"Subtitle was added": "El subtítulo fue agregado",
"Tags": "Etiquetas",
"Terms": "Términos",
"UPLOAD": "SUBIR",
"Up next": "A continuación",
"Upload": "Subir",
"Upload media": "Subir medios",
"Uploads": "Subidas",
"VIEW ALL": "VER TODO",
"View all": "Ver todo",
"comment": "comentario",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "es un CMS de video y medios de código abierto, moderno y completamente equipado. Está desarrollado para satisfacer las necesidades de las plataformas web modernas para ver y compartir medios",
"media in category": "medios en la categoría",
"media in tag": "medios en la etiqueta",
"view": "vista",
"views": "vistas",
"yet": "aún",
}
replacement_strings = {
"Apr": "Abr",
"Aug": "Ago",
"Dec": "Dic",
"Feb": "Feb",
"Jan": "Ene",
"Jul": "Jul",
"Jun": "Jun",
"Mar": "Mar",
"May": "May",
"Nov": "Nov",
"Oct": "Oct",
"Sep": "Sep",
"day ago": "hace un día",
"days ago": "hace días",
"hour ago": "hace una hora",
"hours ago": "hace horas",
"just now": "justo ahora",
"minute ago": "hace un minuto",
"minutes ago": "hace minutos",
"month ago": "hace un mes",
"months ago": "hace meses",
"second ago": "hace un segundo",
"seconds ago": "hace segundos",
"week ago": "hace una semana",
"weeks ago": "hace semanas",
"year ago": "hace un año",
"years ago": "hace años",
}

View File

@ -0,0 +1,105 @@
translation_strings = {
"ABOUT": "À PROPOS",
"AUTOPLAY": "Lecture automatique",
"About": "À propos",
"Add a": "Ajouter un",
"Add a ": "",
"COMMENT": "COMMENTAIRE",
"Categories": "Catégories",
"Category": "Catégorie",
"Change Language": "Changer de langue",
"Change password": "Changer le mot de passe",
"Comment": "Commentaire",
"Comments": "Commentaires",
"Comments are disabled": "Les commentaires sont désactivés",
"Contact": "Contact",
"DELETE MEDIA": "SUPPRIMER LE MÉDIA",
"DOWNLOAD": "TÉLÉCHARGER",
"EDIT MEDIA": "MODIFIER LE MÉDIA",
"EDIT PROFILE": "MODIFIER LE PROFIL",
"EDIT SUBTITLE": "MODIFIER LE SOUS-TITRE",
"Edit media": "Modifier le média",
"Edit profile": "Modifier le profil",
"Edit subtitle": "Modifier le sous-titre",
"Featured": "En vedette",
"Go": "Aller",
"History": "Historique",
"Home": "Accueil",
"Language": "Langue",
"Latest": "Dernier",
"Liked media": "Médias aimés",
"Manage comments": "Gérer les commentaires",
"Manage media": "Gérer les médias",
"Manage users": "Gérer les utilisateurs",
"Media": "Média",
"Media was edited": "Le média a été modifié",
"Members": "Membres",
"My media": "Mes médias",
"My playlists": "Mes playlists",
"No": "Non",
"No comment yet": "Pas encore de commentaire",
"No comments yet": "Pas encore de commentaires",
"No results for": "Aucun résultat pour",
"PLAYLISTS": "PLAYLISTS",
"Playlists": "Playlists",
"Powered by": "Propulsé par",
"Published on": "Publié le",
"Recommended": "Recommandé",
"Register": "S'inscrire",
"SAVE": "ENREGISTRER",
"SEARCH": "RECHERCHER",
"SHARE": "PARTAGER",
"SHOW MORE": "MONTRER PLUS",
"SUBMIT": "SOUMETTRE",
"Search": "Rechercher",
"Select": "Sélectionner",
"Sign in": "Se connecter",
"Sign out": "Se déconnecter",
"Subtitle was added": "Le sous-titre a été ajouté",
"Tags": "Tags",
"Terms": "Conditions",
"UPLOAD": "TÉLÉCHARGER",
"Up next": "À suivre",
"Upload": "Télécharger",
"Upload media": "Télécharger des médias",
"Uploads": "Téléchargements",
"VIEW ALL": "VOIR TOUT",
"View all": "Voir tout",
"comment": "commentaire",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "est un CMS vidéo et média open source moderne et complet. Il est développé pour répondre aux besoins des plateformes web modernes pour la visualisation et le partage de médias",
"media in category": "média dans la catégorie",
"media in tag": "média dans le tag",
"view": "vue",
"views": "vues",
"yet": "encore",
}
replacement_strings = {
"Apr": "Avr",
"Aug": "Aoû",
"Dec": "Déc",
"Feb": "Fév",
"Jan": "Jan",
"Jul": "Juil",
"Jun": "Juin",
"Mar": "Mar",
"May": "Mai",
"Nov": "Nov",
"Oct": "Oct",
"Sep": "Sep",
"day ago": "il y a un jour",
"days ago": "il y a quelques jours",
"hour ago": "il y a une heure",
"hours ago": "il y a quelques heures",
"just now": "à l'instant",
"minute ago": "il y a une minute",
"minutes ago": "il y a quelques minutes",
"month ago": "il y a un mois",
"months ago": "il y a quelques mois",
"second ago": "il y a une seconde",
"seconds ago": "il y a quelques secondes",
"week ago": "il y a une semaine",
"weeks ago": "il y a quelques semaines",
"year ago": "il y a un an",
"years ago": "il y a quelques années",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "के बारे में",
"AUTOPLAY": "स्वतः चलाएं",
"About": "के बारे में",
"Add a ": "जोड़ें",
"COMMENT": "टिप्पणी",
"Categories": "श्रेणियाँ",
"Category": "श्रेणी",
"Change Language": "भाषा बदलें",
"Change password": "पासवर्ड बदलें",
"Comment": "टिप्पणी",
"Comments": "टिप्पणियाँ",
"Comments are disabled": "टिप्पणियाँ अक्षम हैं",
"Contact": "संपर्क करें",
"DELETE MEDIA": "मीडिया हटाएं",
"DOWNLOAD": "डाउनलोड करें",
"EDIT MEDIA": "मीडिया संपादित करें",
"EDIT PROFILE": "प्रोफ़ाइल संपादित करें",
"EDIT SUBTITLE": "उपशीर्षक संपादित करें",
"Edit media": "मीडिया संपादित करें",
"Edit profile": "प्रोफ़ाइल संपादित करें",
"Edit subtitle": "उपशीर्षक संपादित करें",
"Featured": "विशेष रुप से प्रदर्शित",
"Go": "जाएं",
"History": "इतिहास",
"Home": "मुख्य पृष्ठ",
"Language": "भाषा",
"Latest": "नवीनतम",
"Liked media": "पसंदीदा मीडिया",
"Manage comments": "टिप्पणियाँ प्रबंधित करें",
"Manage media": "मीडिया प्रबंधित करें",
"Manage users": "उपयोगकर्ताओं को प्रबंधित करें",
"Media": "मीडिया",
"Media was edited": "मीडिया संपादित किया गया था",
"Members": "सदस्य",
"My media": "मेरा मीडिया",
"My playlists": "मेरी प्लेलिस्ट",
"No": "नहीं",
"No comment yet": "अभी तक कोई टिप्पणी नहीं",
"No comments yet": "अभी तक कोई टिप्पणियाँ नहीं",
"No results for": "के लिए कोई परिणाम नहीं",
"PLAYLISTS": "प्लेलिस्ट",
"Playlists": "प्लेलिस्ट",
"Powered by": "द्वारा संचालित",
"Published on": "पर प्रकाशित",
"Recommended": "अनुशंसित",
"Register": "पंजीकरण करें",
"SAVE": "सहेजें",
"SEARCH": "खोजें",
"SHARE": "साझा करें",
"SHOW MORE": "और दिखाएं",
"SUBMIT": "प्रस्तुत करें",
"Search": "खोजें",
"Select": "चुनें",
"Sign in": "साइन इन करें",
"Sign out": "साइन आउट करें",
"Subtitle was added": "उपशीर्षक जोड़ा गया",
"Tags": "टैग",
"Terms": "शर्तें",
"UPLOAD": "अपलोड करें",
"Up next": "अगला",
"Upload": "अपलोड करें",
"Upload media": "मीडिया अपलोड करें",
"Uploads": "अपलोड",
"VIEW ALL": "सभी देखें",
"View all": "सभी देखें",
"comment": "टिप्पणी",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "एक आधुनिक, पूर्ण विशेषताओं वाला ओपन सोर्स वीडियो और मीडिया CMS है। इसे मीडिया देखने और साझा करने के लिए आधुनिक वेब प्लेटफार्मों की आवश्यकताओं को पूरा करने के लिए विकसित किया गया है",
"media in category": "श्रेणी में मीडिया",
"media in tag": "टैग में मीडिया",
"view": "देखें",
"views": "दृश्य",
"yet": "अभी तक",
}
replacement_strings = {
"Apr": "अप्रैल",
"Aug": "अगस्त",
"Dec": "दिसंबर",
"Feb": "फरवरी",
"Jan": "जनवरी",
"Jul": "जुलाई",
"Jun": "जून",
"Mar": "मार्च",
"May": "मई",
"Nov": "नवंबर",
"Oct": "अक्टूबर",
"Sep": "सितंबर",
"day ago": "दिन पहले",
"days ago": "दिन पहले",
"hour ago": "घंटा पहले",
"hours ago": "घंटे पहले",
"just now": "अभी अभी",
"minute ago": "मिनट पहले",
"minutes ago": "मिनट पहले",
"month ago": "महीना पहले",
"months ago": "महीने पहले",
"second ago": "सेकंड पहले",
"seconds ago": "सेकंड पहले",
"week ago": "सप्ताह पहले",
"weeks ago": "सप्ताह पहले",
"year ago": "साल पहले",
"years ago": "साल पहले",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "TENTANG",
"AUTOPLAY": "PUTAR OTOMATIS",
"About": "Tentang",
"Add a ": "Tambahkan ",
"COMMENT": "KOMENTAR",
"Categories": "Kategori",
"Category": "Kategori",
"Change Language": "Ganti Bahasa",
"Change password": "Ganti kata sandi",
"Comment": "Komentar",
"Comments": "Komentar",
"Comments are disabled": "Komentar dinonaktifkan",
"Contact": "Kontak",
"DELETE MEDIA": "HAPUS MEDIA",
"DOWNLOAD": "UNDUH",
"EDIT MEDIA": "EDIT MEDIA",
"EDIT PROFILE": "EDIT PROFIL",
"EDIT SUBTITLE": "EDIT SUBTITLE",
"Edit media": "Edit media",
"Edit profile": "Edit profil",
"Edit subtitle": "Edit subtitle",
"Featured": "Unggulan",
"Go": "Pergi",
"History": "Riwayat",
"Home": "Beranda",
"Language": "Bahasa",
"Latest": "Terbaru",
"Liked media": "Media yang disukai",
"Manage comments": "Kelola komentar",
"Manage media": "Kelola media",
"Manage users": "Kelola pengguna",
"Media": "Media",
"Media was edited": "Media telah diedit",
"Members": "Anggota",
"My media": "Media saya",
"My playlists": "Daftar putar saya",
"No": "Tidak",
"No comment yet": "Belum ada komentar",
"No comments yet": "Belum ada komentar",
"No results for": "Tidak ada hasil untuk",
"PLAYLISTS": "DAFTAR PUTAR",
"Playlists": "Daftar putar",
"Powered by": "Didukung oleh",
"Published on": "Diterbitkan pada",
"Recommended": "Direkomendasikan",
"Register": "Daftar",
"SAVE": "SIMPAN",
"SEARCH": "CARI",
"SHARE": "BAGIKAN",
"SHOW MORE": "TAMPILKAN LEBIH BANYAK",
"SUBMIT": "KIRIM",
"Search": "Cari",
"Select": "Pilih",
"Sign in": "Masuk",
"Sign out": "Keluar",
"Subtitle was added": "Subtitle telah ditambahkan",
"Tags": "Tag",
"Terms": "Ketentuan",
"UPLOAD": "UNGGAH",
"Up next": "Selanjutnya",
"Upload": "Unggah",
"Upload media": "Unggah media",
"Uploads": "Unggahan",
"VIEW ALL": "LIHAT SEMUA",
"View all": "Lihat semua",
"comment": "komentar",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "adalah CMS video dan media open source yang modern dan lengkap. Ini dikembangkan untuk memenuhi kebutuhan platform web modern untuk menonton dan berbagi media",
"media in category": "media dalam kategori",
"media in tag": "media dalam tag",
"view": "lihat",
"views": "tampilan",
"yet": "belum",
}
replacement_strings = {
"Apr": "Apr",
"Aug": "Agu",
"Dec": "Des",
"Feb": "Feb",
"Jan": "Jan",
"Jul": "Jul",
"Jun": "Jun",
"Mar": "Mar",
"May": "Mei",
"Nov": "Nov",
"Oct": "Okt",
"Sep": "Sep",
"day ago": "hari yang lalu",
"days ago": "hari yang lalu",
"hour ago": "jam yang lalu",
"hours ago": "jam yang lalu",
"just now": "baru saja",
"minute ago": "menit yang lalu",
"minutes ago": "menit yang lalu",
"month ago": "bulan yang lalu",
"months ago": "bulan yang lalu",
"second ago": "detik yang lalu",
"seconds ago": "detik yang lalu",
"week ago": "minggu yang lalu",
"weeks ago": "minggu yang lalu",
"year ago": "tahun yang lalu",
"years ago": "tahun yang lalu",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "",
"AUTOPLAY": "自動再生",
"About": "",
"Add a ": "追加",
"COMMENT": "コメント",
"Categories": "カテゴリー",
"Category": "カテゴリー",
"Change Language": "言語を変更",
"Change password": "パスワードを変更",
"Comment": "コメント",
"Comments": "コメント",
"Comments are disabled": "コメントは無効です",
"Contact": "連絡先",
"DELETE MEDIA": "メディアを削除",
"DOWNLOAD": "ダウンロード",
"EDIT MEDIA": "メディアを編集",
"EDIT PROFILE": "プロフィールを編集",
"EDIT SUBTITLE": "字幕を編集",
"Edit media": "メディアを編集",
"Edit profile": "プロフィールを編集",
"Edit subtitle": "字幕を編集",
"Featured": "注目",
"Go": "行く",
"History": "履歴",
"Home": "ホーム",
"Language": "言語",
"Latest": "最新",
"Liked media": "いいねしたメディア",
"Manage comments": "コメントを管理",
"Manage media": "メディアを管理",
"Manage users": "ユーザーを管理",
"Media": "メディア",
"Media was edited": "メディアが編集されました",
"Members": "メンバー",
"My media": "私のメディア",
"My playlists": "私のプレイリスト",
"No": "いいえ",
"No comment yet": "まだコメントはありません",
"No comments yet": "まだコメントはありません",
"No results for": "の結果はありません",
"PLAYLISTS": "プレイリスト",
"Playlists": "プレイリスト",
"Powered by": "提供",
"Published on": "公開日",
"Recommended": "おすすめ",
"Register": "登録",
"SAVE": "保存",
"SEARCH": "検索",
"SHARE": "共有",
"SHOW MORE": "もっと見る",
"SUBMIT": "送信",
"Search": "検索",
"Select": "選択",
"Sign in": "サインイン",
"Sign out": "サインアウト",
"Subtitle was added": "字幕が追加されました",
"Tags": "タグ",
"Terms": "利用規約",
"UPLOAD": "アップロード",
"Up next": "次に再生",
"Upload": "アップロード",
"Upload media": "メディアをアップロード",
"Uploads": "アップロード",
"VIEW ALL": "すべて表示",
"View all": "すべて表示",
"comment": "コメント",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "は、現代のウェブプラットフォームのニーズに応えるために開発された、最新のフル機能のオープンソースビデオおよびメディアCMSです。",
"media in category": "カテゴリー内のメディア",
"media in tag": "タグ内のメディア",
"view": "ビュー",
"views": "ビュー",
"yet": "まだ",
}
replacement_strings = {
"Apr": "4月",
"Aug": "8月",
"Dec": "12月",
"Feb": "2月",
"Jan": "1月",
"Jul": "7月",
"Jun": "6月",
"Mar": "3月",
"May": "5月",
"Nov": "11月",
"Oct": "10月",
"Sep": "9月",
"day ago": "日前",
"days ago": "日前",
"hour ago": "時間前",
"hours ago": "時間前",
"just now": "たった今",
"minute ago": "分前",
"minutes ago": "分前",
"month ago": "ヶ月前",
"months ago": "ヶ月前",
"second ago": "秒前",
"seconds ago": "秒前",
"week ago": "週間前",
"weeks ago": "週間前",
"year ago": "年前",
"years ago": "年前",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "정보",
"AUTOPLAY": "자동 재생",
"About": "",
"Add a ": "추가",
"COMMENT": "댓글",
"Categories": "카테고리",
"Category": "카테고리",
"Change Language": "언어 변경",
"Change password": "비밀번호 변경",
"Comment": "댓글",
"Comments": "댓글",
"Comments are disabled": "댓글이 비활성화되었습니다",
"Contact": "연락처",
"DELETE MEDIA": "미디어 삭제",
"DOWNLOAD": "다운로드",
"EDIT MEDIA": "미디어 편집",
"EDIT PROFILE": "프로필 편집",
"EDIT SUBTITLE": "자막 편집",
"Edit media": "미디어 편집",
"Edit profile": "프로필 편집",
"Edit subtitle": "자막 편집",
"Featured": "추천",
"Go": "이동",
"History": "기록",
"Home": "",
"Language": "언어",
"Latest": "최신",
"Liked media": "좋아한 미디어",
"Manage comments": "댓글 관리",
"Manage media": "미디어 관리",
"Manage users": "사용자 관리",
"Media": "미디어",
"Media was edited": "미디어가 편집되었습니다",
"Members": "회원",
"My media": "내 미디어",
"My playlists": "내 재생 목록",
"No": "아니요",
"No comment yet": "아직 댓글이 없습니다",
"No comments yet": "아직 댓글이 없습니다",
"No results for": "결과 없음",
"PLAYLISTS": "재생 목록",
"Playlists": "재생 목록",
"Powered by": "제공",
"Published on": "게시일",
"Recommended": "추천",
"Register": "등록",
"SAVE": "저장",
"SEARCH": "검색",
"SHARE": "공유",
"SHOW MORE": "더 보기",
"SUBMIT": "제출",
"Search": "검색",
"Select": "선택",
"Sign in": "로그인",
"Sign out": "로그아웃",
"Subtitle was added": "자막이 추가되었습니다",
"Tags": "태그",
"Terms": "약관",
"UPLOAD": "업로드",
"Up next": "다음",
"Upload": "업로드",
"Upload media": "미디어 업로드",
"Uploads": "업로드",
"VIEW ALL": "모두 보기",
"View all": "모두 보기",
"comment": "댓글",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "현대적인, 완전한 기능을 갖춘 오픈 소스 비디오 및 미디어 CMS입니다. 미디어를 시청하고 공유하기 위한 현대 웹 플랫폼의 요구를 충족시키기 위해 개발되었습니다",
"media in category": "카테고리의 미디어",
"media in tag": "태그의 미디어",
"view": "보기",
"views": "조회수",
"yet": "아직",
}
replacement_strings = {
"Apr": "4월",
"Aug": "8월",
"Dec": "12월",
"Feb": "2월",
"Jan": "1월",
"Jul": "7월",
"Jun": "6월",
"Mar": "3월",
"May": "5월",
"Nov": "11월",
"Oct": "10월",
"Sep": "9월",
"day ago": "일 전",
"days ago": "일 전",
"hour ago": "시간 전",
"hours ago": "시간 전",
"just now": "방금",
"minute ago": "분 전",
"minutes ago": "분 전",
"month ago": "달 전",
"months ago": "달 전",
"second ago": "초 전",
"seconds ago": "초 전",
"week ago": "주 전",
"weeks ago": "주 전",
"year ago": "년 전",
"years ago": "년 전",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "OVER",
"AUTOPLAY": "AUTOMATISCH AFSPELEN",
"About": "",
"Add a ": "Voeg een ",
"COMMENT": "REACTIE",
"Categories": "Categorieën",
"Category": "Categorie",
"Change Language": "Taal wijzigen",
"Change password": "Wachtwoord wijzigen",
"Comment": "Reactie",
"Comments": "Reacties",
"Comments are disabled": "Reacties zijn uitgeschakeld",
"Contact": "Contact",
"DELETE MEDIA": "MEDIA VERWIJDEREN",
"DOWNLOAD": "DOWNLOADEN",
"EDIT MEDIA": "MEDIA BEWERKEN",
"EDIT PROFILE": "PROFIEL BEWERKEN",
"EDIT SUBTITLE": "ONDERTITEL BEWERKEN",
"Edit media": "Media bewerken",
"Edit profile": "Profiel bewerken",
"Edit subtitle": "Ondertitel bewerken",
"Featured": "Aanbevolen",
"Go": "Ga",
"History": "Geschiedenis",
"Home": "Home",
"Language": "Taal",
"Latest": "Laatste",
"Liked media": "Leuke media",
"Manage comments": "Reacties beheren",
"Manage media": "Media beheren",
"Manage users": "Gebruikers beheren",
"Media": "Media",
"Media was edited": "Media is bewerkt",
"Members": "Leden",
"My media": "Mijn media",
"My playlists": "Mijn afspeellijsten",
"No": "Nee",
"No comment yet": "Nog geen reactie",
"No comments yet": "Nog geen reacties",
"No results for": "Geen resultaten voor",
"PLAYLISTS": "AFSPEELLIJSTEN",
"Playlists": "Afspeellijsten",
"Powered by": "Aangedreven door",
"Published on": "Gepubliceerd op",
"Recommended": "Aanbevolen",
"Register": "Registreren",
"SAVE": "OPSLAAN",
"SEARCH": "ZOEKEN",
"SHARE": "DELEN",
"SHOW MORE": "MEER WEERGEVEN",
"SUBMIT": "INDIENEN",
"Search": "Zoeken",
"Select": "Selecteer",
"Sign in": "Inloggen",
"Sign out": "Uitloggen",
"Subtitle was added": "Ondertitel is toegevoegd",
"Tags": "Tags",
"Terms": "Voorwaarden",
"UPLOAD": "UPLOADEN",
"Up next": "Hierna",
"Upload": "Uploaden",
"Upload media": "Media uploaden",
"Uploads": "Uploads",
"VIEW ALL": "BEKIJK ALLES",
"View all": "Bekijk alles",
"comment": "reactie",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "is een modern, volledig uitgerust open source video- en media-CMS. Het is ontwikkeld om te voldoen aan de behoeften van moderne webplatforms voor het bekijken en delen van media",
"media in category": "media in categorie",
"media in tag": "media in tag",
"view": "bekijk",
"views": "weergaven",
"yet": "nog",
}
replacement_strings = {
"Apr": "Apr",
"Aug": "Aug",
"Dec": "Dec",
"Feb": "Feb",
"Jan": "Jan",
"Jul": "Jul",
"Jun": "Jun",
"Mar": "Mrt",
"May": "Mei",
"Nov": "Nov",
"Oct": "Okt",
"Sep": "Sep",
"day ago": "dag geleden",
"days ago": "dagen geleden",
"hour ago": "uur geleden",
"hours ago": "uren geleden",
"just now": "zojuist",
"minute ago": "minuut geleden",
"minutes ago": "minuten geleden",
"month ago": "maand geleden",
"months ago": "maanden geleden",
"second ago": "seconde geleden",
"seconds ago": "seconden geleden",
"week ago": "week geleden",
"weeks ago": "weken geleden",
"year ago": "jaar geleden",
"years ago": "jaren geleden",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "SOBRE",
"AUTOPLAY": "REPRODUÇÃO AUTOMÁTICA",
"About": "",
"Add a ": "Adicionar um ",
"COMMENT": "COMENTÁRIO",
"Categories": "Categorias",
"Category": "Categoria",
"Change Language": "Mudar idioma",
"Change password": "Mudar senha",
"Comment": "Comentário",
"Comments": "Comentários",
"Comments are disabled": "Comentários estão desativados",
"Contact": "Contato",
"DELETE MEDIA": "EXCLUIR MÍDIA",
"DOWNLOAD": "BAIXAR",
"EDIT MEDIA": "EDITAR MÍDIA",
"EDIT PROFILE": "EDITAR PERFIL",
"EDIT SUBTITLE": "EDITAR LEGENDA",
"Edit media": "Editar mídia",
"Edit profile": "Editar perfil",
"Edit subtitle": "Editar legenda",
"Featured": "Destaque",
"Go": "Ir",
"History": "Histórico",
"Home": "Início",
"Language": "Idioma",
"Latest": "Últimos",
"Liked media": "Mídia curtida",
"Manage comments": "Gerenciar comentários",
"Manage media": "Gerenciar mídia",
"Manage users": "Gerenciar usuários",
"Media": "Mídia",
"Media was edited": "Mídia foi editada",
"Members": "Membros",
"My media": "Minhas mídias",
"My playlists": "Minhas playlists",
"No": "Não",
"No comment yet": "Nenhum comentário ainda",
"No comments yet": "Nenhum comentário ainda",
"No results for": "Nenhum resultado para",
"PLAYLISTS": "PLAYLISTS",
"Playlists": "Playlists",
"Powered by": "Desenvolvido por",
"Published on": "Publicado em",
"Recommended": "Recomendado",
"Register": "Registrar",
"SAVE": "SALVAR",
"SEARCH": "PESQUISAR",
"SHARE": "COMPARTILHAR",
"SHOW MORE": "MOSTRAR MAIS",
"SUBMIT": "ENVIAR",
"Search": "Pesquisar",
"Select": "Selecionar",
"Sign in": "Entrar",
"Sign out": "Sair",
"Subtitle was added": "Legenda foi adicionada",
"Tags": "Tags",
"Terms": "Termos",
"UPLOAD": "CARREGAR",
"Up next": "A seguir",
"Upload": "Carregar",
"Upload media": "Carregar mídia",
"Uploads": "Uploads",
"VIEW ALL": "VER TODOS",
"View all": "Ver todos",
"comment": "comentário",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "é um CMS de vídeo e mídia de código aberto, moderno e completo. Foi desenvolvido para atender às necessidades das plataformas web modernas para visualização e compartilhamento de mídia",
"media in category": "mídia na categoria",
"media in tag": "mídia na tag",
"view": "visualização",
"views": "visualizações",
"yet": "ainda",
}
replacement_strings = {
"Apr": "Abr",
"Aug": "Ago",
"Dec": "Dez",
"Feb": "Fev",
"Jan": "Jan",
"Jul": "Jul",
"Jun": "Jun",
"Mar": "Mar",
"May": "Mai",
"Nov": "Nov",
"Oct": "Out",
"Sep": "Set",
"day ago": "dia atrás",
"days ago": "dias atrás",
"hour ago": "hora atrás",
"hours ago": "horas atrás",
"just now": "agora mesmo",
"minute ago": "minuto atrás",
"minutes ago": "minutos atrás",
"month ago": "mês atrás",
"months ago": "meses atrás",
"second ago": "segundo atrás",
"seconds ago": "segundos atrás",
"week ago": "semana atrás",
"weeks ago": "semanas atrás",
"year ago": "ano atrás",
"years ago": "anos atrás",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "О",
"AUTOPLAY": "Автовоспроизведение",
"About": "",
"Add a ": "Добавить ",
"COMMENT": "КОММЕНТАРИЙ",
"Categories": "Категории",
"Category": "Категория",
"Change Language": "Изменить язык",
"Change password": "Изменить пароль",
"Comment": "Комментарий",
"Comments": "Комментарии",
"Comments are disabled": "Комментарии отключены",
"Contact": "Контакт",
"DELETE MEDIA": "УДАЛИТЬ МЕДИА",
"DOWNLOAD": "СКАЧАТЬ",
"EDIT MEDIA": "РЕДАКТИРОВАТЬ МЕДИА",
"EDIT PROFILE": "РЕДАКТИРОВАТЬ ПРОФИЛЬ",
"EDIT SUBTITLE": "РЕДАКТИРОВАТЬ СУБТИТРЫ",
"Edit media": "Редактировать медиа",
"Edit profile": "Редактировать профиль",
"Edit subtitle": "Редактировать субтитры",
"Featured": "Рекомендуемое",
"Go": "Перейти",
"History": "История",
"Home": "Главная",
"Language": "Язык",
"Latest": "Последние",
"Liked media": "Понравившиеся медиа",
"Manage comments": "Управление комментариями",
"Manage media": "Управление медиа",
"Manage users": "Управление пользователями",
"Media": "Медиа",
"Media was edited": "Медиа было отредактировано",
"Members": "Участники",
"My media": "Мои медиа",
"My playlists": "Мои плейлисты",
"No": "Нет",
"No comment yet": "Комментариев пока нет",
"No comments yet": "Комментариев пока нет",
"No results for": "Нет результатов для",
"PLAYLISTS": "ПЛЕЙЛИСТЫ",
"Playlists": "Плейлисты",
"Powered by": "Работает на",
"Published on": "Опубликовано",
"Recommended": "Рекомендуемое",
"Register": "Регистрация",
"SAVE": "СОХРАНИТЬ",
"SEARCH": "ПОИСК",
"SHARE": "ПОДЕЛИТЬСЯ",
"SHOW MORE": "ПОКАЗАТЬ БОЛЬШЕ",
"SUBMIT": "ОТПРАВИТЬ",
"Search": "Поиск",
"Select": "Выбрать",
"Sign in": "Войти",
"Sign out": "Выйти",
"Subtitle was added": "Субтитры были добавлены",
"Tags": "Теги",
"Terms": "Условия",
"UPLOAD": "ЗАГРУЗИТЬ",
"Up next": "Далее",
"Upload": "Загрузить",
"Upload media": "Загрузить медиа",
"Uploads": "Загрузки",
"VIEW ALL": "ПОКАЗАТЬ ВСЕ",
"View all": "Показать все",
"comment": "комментарий",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "это современная, полнофункциональная система управления видео и медиа с открытым исходным кодом. Она разработана для удовлетворения потребностей современных веб-платформ для просмотра и обмена медиа",
"media in category": "медиа в категории",
"media in tag": "медиа в теге",
"view": "просмотр",
"views": "просмотры",
"yet": "еще",
}
replacement_strings = {
"Apr": "Апр",
"Aug": "Авг",
"Dec": "Дек",
"Feb": "Фев",
"Jan": "Янв",
"Jul": "Июл",
"Jun": "Июн",
"Mar": "Мар",
"May": "Май",
"Nov": "Ноя",
"Oct": "Окт",
"Sep": "Сен",
"day ago": "день назад",
"days ago": "дней назад",
"hour ago": "час назад",
"hours ago": "часов назад",
"just now": "только что",
"minute ago": "минуту назад",
"minutes ago": "минут назад",
"month ago": "месяц назад",
"months ago": "месяцев назад",
"second ago": "секунду назад",
"seconds ago": "секунд назад",
"week ago": "неделю назад",
"weeks ago": "недель назад",
"year ago": "год назад",
"years ago": "лет назад",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "HAKKINDA",
"AUTOPLAY": "OTOMATİK OYNATMA",
"About": "",
"Add a ": "Ekle ",
"COMMENT": "YORUM",
"Categories": "Kategoriler",
"Category": "Kategori",
"Change Language": "Dili Değiştir",
"Change password": "Şifreyi Değiştir",
"Comment": "Yorum",
"Comments": "Yorumlar",
"Comments are disabled": "Yorumlar devre dışı",
"Contact": "İletişim",
"DELETE MEDIA": "MEDYAYI SİL",
"DOWNLOAD": "İNDİR",
"EDIT MEDIA": "MEDYAYI DÜZENLE",
"EDIT PROFILE": "PROFİLİ DÜZENLE",
"EDIT SUBTITLE": "ALT YAZIYI DÜZENLE",
"Edit media": "Medyayı düzenle",
"Edit profile": "Profili düzenle",
"Edit subtitle": "Alt yazıyı düzenle",
"Featured": "Öne Çıkan",
"Go": "Git",
"History": "Geçmiş",
"Home": "Ana Sayfa",
"Language": "Dil",
"Latest": "En Son",
"Liked media": "Beğenilen medya",
"Manage comments": "Yorumları yönet",
"Manage media": "Medyayı yönet",
"Manage users": "Kullanıcıları yönet",
"Media": "Medya",
"Media was edited": "Medya düzenlendi",
"Members": "Üyeler",
"My media": "Medyam",
"My playlists": "Çalma listelerim",
"No": "Hayır",
"No comment yet": "Henüz yorum yok",
"No comments yet": "Henüz yorum yok",
"No results for": "Sonuç bulunamadı",
"PLAYLISTS": "ÇALMA LİSTELERİ",
"Playlists": "Çalma listeleri",
"Powered by": "Tarafından desteklenmektedir",
"Published on": "Yayınlanma tarihi",
"Recommended": "Önerilen",
"Register": "Kayıt Ol",
"SAVE": "KAYDET",
"SEARCH": "ARA",
"SHARE": "PAYLAŞ",
"SHOW MORE": "DAHA FAZLA GÖSTER",
"SUBMIT": "GÖNDER",
"Search": "Ara",
"Select": "Seç",
"Sign in": "Giriş Yap",
"Sign out": "Çıkış Yap",
"Subtitle was added": "Alt yazı eklendi",
"Tags": "Etiketler",
"Terms": "Şartlar",
"UPLOAD": "YÜKLE",
"Up next": "Sıradaki",
"Upload": "Yükle",
"Upload media": "Medya yükle",
"Uploads": "Yüklemeler",
"VIEW ALL": "HEPSİNİ GÖR",
"View all": "Hepsini gör",
"comment": "yorum",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "modern, tam özellikli açık kaynaklı bir video ve medya CMS'sidir. Medya izleme ve paylaşma ihtiyaçlarını karşılamak için geliştirilmiştir",
"media in category": "kategorideki medya",
"media in tag": "etiketteki medya",
"view": "görünüm",
"views": "görünümler",
"yet": "henüz",
}
replacement_strings = {
"Apr": "Nis",
"Aug": "Ağu",
"Dec": "Ara",
"Feb": "Şub",
"Jan": "Oca",
"Jul": "Tem",
"Jun": "Haz",
"Mar": "Mar",
"May": "May",
"Nov": "Kas",
"Oct": "Eki",
"Sep": "Eyl",
"day ago": "gün önce",
"days ago": "gün önce",
"hour ago": "saat önce",
"hours ago": "saat önce",
"just now": "şimdi",
"minute ago": "dakika önce",
"minutes ago": "dakika önce",
"month ago": "ay önce",
"months ago": "ay önce",
"second ago": "saniye önce",
"seconds ago": "saniye önce",
"week ago": "hafta önce",
"weeks ago": "hafta önce",
"year ago": "yıl önce",
"years ago": "yıl önce",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "کے بارے میں",
"AUTOPLAY": "خودکار پلے",
"About": "",
"Add a ": "شامل کریں",
"COMMENT": "تبصرہ",
"Categories": "اقسام",
"Category": "قسم",
"Change Language": "زبان تبدیل کریں",
"Change password": "پاس ورڈ تبدیل کریں",
"Comment": "تبصرہ",
"Comments": "تبصرے",
"Comments are disabled": "تبصرے غیر فعال ہیں",
"Contact": "رابطہ کریں",
"DELETE MEDIA": "میڈیا حذف کریں",
"DOWNLOAD": "ڈاؤن لوڈ",
"EDIT MEDIA": "میڈیا ترمیم کریں",
"EDIT PROFILE": "پروفائل ترمیم کریں",
"EDIT SUBTITLE": "سب ٹائٹل ترمیم کریں",
"Edit media": "میڈیا ترمیم کریں",
"Edit profile": "پروفائل ترمیم کریں",
"Edit subtitle": "سب ٹائٹل ترمیم کریں",
"Featured": "نمایاں",
"Go": "جائیں",
"History": "تاریخ",
"Home": "ہوم",
"Language": "زبان",
"Latest": "تازہ ترین",
"Liked media": "پسندیدہ میڈیا",
"Manage comments": "تبصرے منظم کریں",
"Manage media": "میڈیا منظم کریں",
"Manage users": "صارفین منظم کریں",
"Media": "میڈیا",
"Media was edited": "میڈیا ترمیم کیا گیا",
"Members": "اراکین",
"My media": "میرا میڈیا",
"My playlists": "میری پلے لسٹس",
"No": "نہیں",
"No comment yet": "ابھی تک کوئی تبصرہ نہیں",
"No comments yet": "ابھی تک کوئی تبصرے نہیں",
"No results for": "کے لئے کوئی نتائج نہیں",
"PLAYLISTS": "پلے لسٹس",
"Playlists": "پلے لسٹس",
"Powered by": "کے ذریعہ تقویت یافتہ",
"Published on": "پر شائع ہوا",
"Recommended": "تجویز کردہ",
"Register": "رجسٹر کریں",
"SAVE": "محفوظ کریں",
"SEARCH": "تلاش کریں",
"SHARE": "شیئر کریں",
"SHOW MORE": "مزید دکھائیں",
"SUBMIT": "جمع کرائیں",
"Search": "تلاش کریں",
"Select": "منتخب کریں",
"Sign in": "سائن ان کریں",
"Sign out": "سائن آؤٹ کریں",
"Subtitle was added": "سب ٹائٹل شامل کیا گیا",
"Tags": "ٹیگز",
"Terms": "شرائط",
"UPLOAD": "اپ لوڈ کریں",
"Up next": "اگلا",
"Upload": "اپ لوڈ کریں",
"Upload media": "میڈیا اپ لوڈ کریں",
"Uploads": "اپ لوڈز",
"VIEW ALL": "سب دیکھیں",
"View all": "سب دیکھیں",
"comment": "تبصرہ",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "ایک جدید، مکمل خصوصیات والا اوپن سورس ویڈیو اور میڈیا CMS ہے۔ یہ جدید ویب پلیٹ فارمز کی ضروریات کو پورا کرنے کے لئے تیار کیا گیا ہے تاکہ میڈیا دیکھنے اور شیئر کرنے کے لئے",
"media in category": "زمرے میں میڈیا",
"media in tag": "ٹیگ میں میڈیا",
"view": "دیکھیں",
"views": "دیکھے گئے",
"yet": "ابھی تک",
}
replacement_strings = {
"Apr": "اپریل",
"Aug": "اگست",
"Dec": "دسمبر",
"Feb": "فروری",
"Jan": "جنوری",
"Jul": "جولائی",
"Jun": "جون",
"Mar": "مارچ",
"May": "مئی",
"Nov": "نومبر",
"Oct": "اکتوبر",
"Sep": "ستمبر",
"day ago": "ایک دن پہلے",
"days ago": "دن پہلے",
"hour ago": "ایک گھنٹہ پہلے",
"hours ago": "گھنٹے پہلے",
"just now": "ابھی",
"minute ago": "ایک منٹ پہلے",
"minutes ago": "منٹ پہلے",
"month ago": "ایک مہینہ پہلے",
"months ago": "مہینے پہلے",
"second ago": "ایک سیکنڈ پہلے",
"seconds ago": "سیکنڈ پہلے",
"week ago": "ایک ہفتہ پہلے",
"weeks ago": "ہفتے پہلے",
"year ago": "ایک سال پہلے",
"years ago": "سال پہلے",
}

View File

@ -0,0 +1,104 @@
translation_strings = {
"ABOUT": "关于",
"AUTOPLAY": "自动播放",
"About": "",
"Add a ": "添加一个",
"COMMENT": "评论",
"Categories": "分类",
"Category": "类别",
"Change Language": "更改语言",
"Change password": "更改密码",
"Comment": "评论",
"Comments": "评论",
"Comments are disabled": "评论已禁用",
"Contact": "联系",
"DELETE MEDIA": "删除媒体",
"DOWNLOAD": "下载",
"EDIT MEDIA": "编辑媒体",
"EDIT PROFILE": "编辑个人资料",
"EDIT SUBTITLE": "编辑字幕",
"Edit media": "编辑媒体",
"Edit profile": "编辑个人资料",
"Edit subtitle": "编辑字幕",
"Featured": "精选",
"Go": "",
"History": "历史",
"Home": "主页",
"Language": "语言",
"Latest": "最新",
"Liked media": "喜欢的媒体",
"Manage comments": "管理评论",
"Manage media": "管理媒体",
"Manage users": "管理用户",
"Media": "媒体",
"Media was edited": "媒体已编辑",
"Members": "成员",
"My media": "我的媒体",
"My playlists": "我的播放列表",
"No": "",
"No comment yet": "还没有评论",
"No comments yet": "还没有评论",
"No results for": "没有结果",
"PLAYLISTS": "播放列表",
"Playlists": "播放列表",
"Powered by": "由...提供技术支持",
"Published on": "发布于",
"Recommended": "推荐",
"Register": "注册",
"SAVE": "保存",
"SEARCH": "搜索",
"SHARE": "分享",
"SHOW MORE": "显示更多",
"SUBMIT": "提交",
"Search": "搜索",
"Select": "选择",
"Sign in": "登录",
"Sign out": "登出",
"Subtitle was added": "字幕已添加",
"Tags": "标签",
"Terms": "条款",
"UPLOAD": "上传",
"Up next": "接下来",
"Upload": "上传",
"Upload media": "上传媒体",
"Uploads": "上传",
"VIEW ALL": "查看全部",
"View all": "查看全部",
"comment": "评论",
"is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media": "是一个现代化、功能齐全的开源视频和媒体CMS。它是为了满足现代网络平台观看和分享媒体的需求而开发的",
"media in category": "类别中的媒体",
"media in tag": "标签中的媒体",
"view": "查看",
"views": "查看",
"yet": "",
}
replacement_strings = {
"Apr": "四月",
"Aug": "八月",
"Dec": "十二月",
"Feb": "二月",
"Jan": "一月",
"Jul": "七月",
"Jun": "六月",
"Mar": "三月",
"May": "五月",
"Nov": "十一月",
"Oct": "十月",
"Sep": "九月",
"day ago": "天前",
"days ago": "天前",
"hour ago": "小时前",
"hours ago": "小时前",
"just now": "刚刚",
"minute ago": "分钟前",
"minutes ago": "分钟前",
"month ago": "月前",
"months ago": "月前",
"second ago": "秒前",
"seconds ago": "秒前",
"week ago": "周前",
"weeks ago": "周前",
"year ago": "年前",
"years ago": "年前",
}

View File

@ -0,0 +1,55 @@
import importlib
import os
from collections import OrderedDict
from django.conf import settings
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Process translation files to add missing keys and sort them'
def handle(self, *args, **options):
translations_dir = os.path.join(settings.BASE_DIR, 'files', 'frontend_translations')
self.process_translation_files(translations_dir)
self.stdout.write(self.style.SUCCESS('Successfully processed translation files'))
def process_translation_files(self, translations_dir):
files = os.listdir(translations_dir)
files = [f for f in files if f.endswith('.py') and f not in ('__init__.py', 'en.py')]
# Import the original English translations
from files.frontend_translations.en import replacement_strings, translation_strings
for file in files:
file_path = os.path.join(translations_dir, file)
module_name = f"files.frontend_translations.{file[:-3]}"
module = importlib.import_module(module_name)
translation_strings_wip = getattr(module, 'translation_strings', {})
replacement_strings_wip = getattr(module, 'replacement_strings', {})
for key in translation_strings:
if key not in translation_strings_wip:
translation_strings_wip[key] = translation_strings[key]
translation_strings_wip = OrderedDict(sorted(translation_strings_wip.items()))
for key in replacement_strings:
if key not in replacement_strings_wip:
replacement_strings_wip[key] = replacement_strings[key]
replacement_strings_wip = OrderedDict(sorted(replacement_strings_wip.items()))
with open(file_path, 'w') as f:
f.write("translation_strings = {\n")
for key, value in translation_strings_wip.items():
f.write(f' "{key}": "{value}",\n')
f.write("}\n\n")
f.write("replacement_strings = {\n")
for key, value in replacement_strings_wip.items():
f.write(f' "{key}": "{value}",\n')
f.write("}\n")
self.stdout.write(self.style.SUCCESS(f'Processed {file}'))

View File

@ -23,17 +23,7 @@ from users.models import User
from .backends import FFmpegBackend
from .exceptions import VideoEncodingError
from .helpers import (
calculate_seconds,
create_temp_file,
get_file_name,
get_file_type,
media_file_info,
produce_ffmpeg_commands,
produce_friendly_token,
rm_file,
run_command,
)
from .helpers import calculate_seconds, create_temp_file, get_file_name, get_file_type, media_file_info, produce_ffmpeg_commands, produce_friendly_token, rm_file, run_command
from .methods import list_tasks, notify_users, pre_save_action
from .models import Category, EncodeProfile, Encoding, Media, Rating, Tag

View File

View File

@ -0,0 +1,11 @@
from django import template
from files.frontend_translations import translate_string
register = template.Library()
@register.filter
def custom_translate(string, lang_code):
return translate_string(lang_code, string)

View File

@ -7,8 +7,10 @@ from . import management_views, views
from .feeds import IndexRSSFeed, SearchRSSFeed
urlpatterns = [
path("i18n/", include("django.conf.urls.i18n")),
re_path(r"^$", views.index),
re_path(r"^about", views.about, name="about"),
re_path(r"^setlanguage", views.setlanguage, name="setlanguage"),
re_path(r"^add_subtitle", views.add_subtitle, name="add_subtitle"),
re_path(r"^categories$", views.categories, name="categories"),
re_path(r"^contact$", views.contact, name="contact"),

View File

@ -12,27 +12,18 @@ from drf_yasg import openapi as openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import permissions, status
from rest_framework.exceptions import PermissionDenied
from rest_framework.parsers import (
FileUploadParser,
FormParser,
JSONParser,
MultiPartParser,
)
from rest_framework.parsers import FileUploadParser, FormParser, JSONParser, MultiPartParser
from rest_framework.response import Response
from rest_framework.settings import api_settings
from rest_framework.views import APIView
from actions.models import USER_MEDIA_ACTIONS, MediaAction
from cms.custom_pagination import FastPaginationWithoutCount
from cms.permissions import (
IsAuthorizedToAdd,
IsAuthorizedToAddComment,
IsUserOrEditor,
user_allowed_to_upload,
)
from cms.permissions import IsAuthorizedToAdd, IsAuthorizedToAddComment, IsUserOrEditor, user_allowed_to_upload
from users.models import User
from .forms import ContactForm, MediaForm, SubtitleForm
from .frontend_translations import translate_string
from .helpers import clean_query, get_alphanumeric_only, produce_ffmpeg_commands
from .methods import (
check_comment_for_mention,
@ -45,16 +36,7 @@ from .methods import (
show_related_media,
update_user_ratings,
)
from .models import (
Category,
Comment,
EncodeProfile,
Encoding,
Media,
Playlist,
PlaylistMedia,
Tag,
)
from .models import Category, Comment, EncodeProfile, Encoding, Media, Playlist, PlaylistMedia, Tag
from .serializers import (
CategorySerializer,
CommentSerializer,
@ -79,6 +61,13 @@ def about(request):
return render(request, "cms/about.html", context)
def setlanguage(request):
"""Set Language view"""
context = {}
return render(request, "cms/set_language.html", context)
@login_required
def add_subtitle(request):
"""Add subtitle view"""
@ -97,7 +86,8 @@ def add_subtitle(request):
form = SubtitleForm(media, request.POST, request.FILES)
if form.is_valid():
subtitle = form.save()
messages.add_message(request, messages.INFO, "Subtitle was added!")
messages.add_message(request, messages.INFO, translate_string(request.LANGUAGE_CODE, "Subtitle was added"))
return HttpResponseRedirect(subtitle.media.get_absolute_url())
else:
form = SubtitleForm(media_item=media)
@ -194,7 +184,7 @@ def edit_media(request):
tag = Tag.objects.create(title=tag, user=request.user)
if tag not in media.tags.all():
media.tags.add(tag)
messages.add_message(request, messages.INFO, "Media was edited!")
messages.add_message(request, messages.INFO, translate_string(request.LANGUAGE_CODE, "Media was edited"))
return HttpResponseRedirect(media.get_absolute_url())
else:
form = MediaForm(request.user, instance=media)
@ -292,7 +282,7 @@ def search(request):
"""Search view"""
context = {}
RSS_URL = f"/rss{request.environ['REQUEST_URI']}"
RSS_URL = f"/rss{request.environ.get('REQUEST_URI')}"
context["RSS_URL"] = RSS_URL
return render(request, "cms/search.html", context)

View File

@ -1,4 +1,5 @@
import React from 'react';
import { translateString } from '../utils/helpers/';
interface MediaListHeaderProps {
title?: string;
@ -9,7 +10,7 @@ interface MediaListHeaderProps {
}
export const MediaListHeader: React.FC<MediaListHeaderProps> = (props) => {
const viewAllText = props.viewAllText || 'VIEW ALL';
const viewAllText = props.viewAllText || translateString('VIEW ALL');
return (
<div className={(props.className ? props.className + ' ' : '') + 'media-list-header'} style={props.style}>
<h2>{props.title}</h2>

View File

@ -7,20 +7,22 @@ import { PageStore, MediaPageStore } from '../../utils/stores/';
import { PageActions, MediaPageActions } from '../../utils/actions/';
import { LinksContext, MemberContext, SiteContext } from '../../utils/contexts/';
import { PopupMain, UserThumbnail } from '../_shared';
import { replaceString } from '../../utils/helpers/';
import './videojs-markers.js';
import './videojs.markers.css';
import {enableMarkers, addMarker} from './videojs-markers_config.js'
import { translateString } from '../../utils/helpers/';
import './Comments.scss';
const commentsText = {
single: 'comment',
uppercaseSingle: 'COMMENT',
ucfirstSingle: 'Comment',
ucfirstPlural: 'Comments',
submitCommentText: 'SUBMIT',
disabledCommentsMsg: 'Comments are disabled',
single: translateString('comment'),
uppercaseSingle: translateString('COMMENT'),
ucfirstSingle: translateString('Comment'),
ucfirstPlural: translateString('Comments'),
submitCommentText: translateString('SUBMIT'),
disabledCommentsMsg: translateString('Comments are disabled'),
};
function CommentForm(props) {
@ -149,7 +151,7 @@ function CommentForm(props) {
inputRef={textareaRef}
className="form-textarea"
rows="1"
placeholder={'Add a ' + commentsText.single + '...'}
placeholder={translateString('Add a ') + commentsText.single + '...'}
value={value}
onChange={onChangeWithMention}
onFocus={onFocus}
@ -164,7 +166,7 @@ function CommentForm(props) {
ref={textareaRef}
className="form-textarea"
rows="1"
placeholder={'Add a ' + commentsText.single + '...'}
placeholder={translateString('Add a ') + commentsText.single + '...'}
value={value}
onChange={onChange}
onFocus={onFocus}
@ -189,9 +191,9 @@ function CommentForm(props) {
href={loginUrl}
rel="noffolow"
className="form-textarea-wrap"
title={'Add a ' + commentsText.single + '...'}
title={translateString('Add a ') + commentsText.single + '...'}
>
<span className="form-textarea">{'Add a ' + commentsText.single + '...'}</span>
<span className="form-textarea">{translateString('Add a ') + commentsText.single + '...'}</span>
</a>
<div className="form-buttons">
<a href={loginUrl} rel="noffolow" className="disabled">
@ -237,7 +239,7 @@ function CommentActions(props) {
{MemberContext._currentValue.can.deleteComment ? (
<div className="comment-action remove-comment">
<PopupTrigger contentRef={popupContentRef}>
<button>DELETE {commentsText.uppercaseSingle}</button>
<button>{translateString('DELETE')} {commentsText.uppercaseSingle}</button>
</PopupTrigger>
<PopupContent contentRef={popupContentRef}>
@ -310,7 +312,7 @@ function Comment(props) {
{props.author_name}
</a>
</div>
<div className="comment-date">{format(new Date(props.publish_date))}</div>
<div className="comment-date">{replaceString(format(new Date(props.publish_date)))}</div>
</div>
<div ref={commentTextRef} className={'comment-text' + (viewMoreContent ? ' show-all' : '')}>
<div
@ -411,7 +413,7 @@ const CommentsListHeader = ({ commentsLength }) => {
? commentsLength + ' ' + commentsText.ucfirstPlural
: commentsLength + ' ' + commentsText.ucfirstSingle
: MediaPageStore.get('media-data').enable_comments
? 'No ' + commentsText.single + ' yet'
? translateString('No') + commentsText.single + translateString('yet')
: ''}
</h2>
) : null}

View File

@ -2,6 +2,7 @@ import React from 'react';
import { format } from 'timeago.js';
import { formatViewsNumber, imageExtension } from '../../../../utils/helpers/';
import { VideoPlayerByPageLink } from '../../../video-player/VideoPlayerByPageLink';
import { translateString } from '../../../../utils/helpers/';
export function ItemDescription(props) {
return '' === props.description ? null : (
@ -73,8 +74,8 @@ export function MediaItemEditLink(props) {
}
return !link ? null : (
<a href={link} title="Edit media" className="item-edit-link">
EDIT MEDIA
<a href={link} title={translateString("Edit media")} className="item-edit-link">
{translateString("EDIT MEDIA")}
</a>
);
}
@ -135,7 +136,7 @@ export function MediaItemAuthorLink(props) {
export function MediaItemMetaViews(props) {
return (
<span className="item-views">{formatViewsNumber(props.views) + ' ' + (1 >= props.views ? 'view' : 'views')}</span>
<span className="item-views">{formatViewsNumber(props.views) + ' ' + (1 >= props.views ? translateString('view') : translateString('views'))}</span>
);
}

View File

@ -8,6 +8,7 @@ import { PendingItemsList } from '../../item-list/PendingItemsList.jsx';
import { renderManageItems } from './includes/functions';
import initManageItemsList from './includes/initManageItemsList';
import { ManageItemsListHandler } from './includes/ManageItemsListHandler';
import { translateString } from '../../../utils/helpers/';
import './ManageItemList.scss';
@ -102,7 +103,7 @@ function useManageItemListSync(props) {
return 1 > listHandler.totalPages() || listHandler.loadedAllItems() ? null : (
<button className="load-more" onClick={onClickLoadMore}>
SHOW MORE
{translateString("SHOW MORE")}
</button>
);
}

View File

@ -2,6 +2,7 @@ import React, { useState } from 'react';
import { usePopup } from '../../utils/hooks/';
import { CircleIconButton, MaterialIcon, NavigationContentApp, PopupMain } from '../_shared/';
import { PlaylistsSelection } from '../playlists-selection/PlaylistsSelection';
import { translateString } from '../../utils/helpers/';
function mediaSavePopupPages(onTriggerPopupClose) {
return {
@ -39,7 +40,7 @@ export function MediaSaveButton(props) {
<CircleIconButton type="span">
<MaterialIcon type="playlist_add" />
</CircleIconButton>
<span>SAVE</span>
<span>{translateString("SAVE")}</span>
</button>
</PopupTrigger>

View File

@ -3,6 +3,7 @@ import { usePopup } from '../../utils/hooks/';
import { CircleIconButton, MaterialIcon, NavigationContentApp, PopupMain } from '../_shared/';
import { MediaShareEmbed } from './MediaShareEmbed';
import { MediaShareOptions } from './MediaShareOptions';
import { translateString } from '../../utils/helpers/';
function mediaSharePopupPages() {
return {
@ -54,7 +55,7 @@ export function MediaShareButton(props) {
<CircleIconButton type="span">
<MaterialIcon type="share" />
</CircleIconButton>
<span>SHARE</span>
<span>{translateString("SHARE")}</span>
</button>
</PopupTrigger>

View File

@ -4,6 +4,7 @@ import { SiteContext } from '../../utils/contexts/';
import { MediaPageStore } from '../../utils/stores/';
import { formatInnerLink } from '../../utils/helpers/';
import { CircleIconButton, MaterialIcon, NavigationContentApp, NavigationMenuList, PopupMain } from '../_shared/';
import { translateString } from '../../utils/helpers/';
function downloadOptionsList() {
const media_data = MediaPageStore.get('media-data');
@ -71,7 +72,7 @@ export function VideoMediaDownloadLink(props) {
<CircleIconButton type="span">
<MaterialIcon type="arrow_downward" />
</CircleIconButton>
<span>DOWNLOAD</span>
<span>{translateString("DOWNLOAD")}</span>
</button>
</PopupTrigger>

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { PageActions } from '../../utils/actions/';
import { PageStore, MediaPageStore } from '../../utils/stores/';
import { ItemList } from '../item-list/ItemList';
import { translateString } from '../../utils/helpers/';
function autoPlayMedia() {
const dt = MediaPageStore.get('media-data');
@ -38,10 +39,10 @@ export function AutoPlay(props) {
return !media ? null : (
<div className="auto-play">
<div className="auto-play-header">
<div className="next-label">Up next</div>
<div className="next-label">{translateString("Up next")}</div>
<div className="auto-play-option">
<label className="checkbox-label right-selectbox" tabIndex={0} onKeyPress={onKeyPress}>
AUTOPLAY
{translateString("AUTOPLAY")}
<span className="checkbox-switcher-wrap">
<span className="checkbox-switcher">
<input

View File

@ -6,6 +6,8 @@ import { PageActions, MediaPageActions } from '../../utils/actions/';
import { formatInnerLink, publishedOnDate } from '../../utils/helpers/';
import { PopupMain } from '../_shared/';
import CommentsList from '../comments/Comments';
import { replaceString } from '../../utils/helpers/';
import { translateString } from '../../utils/helpers/';
function metafield(arr) {
let i;
@ -48,7 +50,7 @@ function MediaAuthorBanner(props) {
</a>
</span>
{PageStore.get('config-media-item').displayPublishDate && props.published ? (
<span className="author-banner-date">Published on {publishedOnDate(new Date(props.published))}</span>
<span className="author-banner-date">{translateString("Published on")} {replaceString(publishedOnDate(new Date(props.published)))}</span>
) : null}
</div>
</div>
@ -76,8 +78,8 @@ function EditMediaButton(props) {
}
return (
<a href={link} rel="nofollow" title="Edit media" className="edit-media">
EDIT MEDIA
<a href={link} rel="nofollow" title={translateString("Edit media")} className="edit-media">
{translateString("EDIT MEDIA")}
</a>
);
}
@ -90,8 +92,8 @@ function EditSubtitleButton(props) {
}
return (
<a href={link} rel="nofollow" title="Edit subtitle" className="edit-subtitle">
EDIT SUBTITLE
<a href={link} rel="nofollow" title={translateString("Edit subtitle")} className="edit-subtitle">
{translateString("EDIT SUBTITLE")}
</a>
);
}
@ -195,12 +197,12 @@ export default function ViewerInfoContent(props) {
</button>
) : null}
{tagsContent.length ? (
<MediaMetaField value={tagsContent} title={1 < tagsContent.length ? 'Tags' : 'Tag'} id="tags" />
<MediaMetaField value={tagsContent} title={1 < tagsContent.length ? translateString('Tags') : translateString('Tag')} id="tags" />
) : null}
{categoriesContent.length ? (
<MediaMetaField
value={categoriesContent}
title={1 < categoriesContent.length ? 'Categories' : 'Category'}
title={1 < categoriesContent.length ? translateString('Categories') : translateString('Category')}
id="categories"
/>
) : null}
@ -215,7 +217,7 @@ export default function ViewerInfoContent(props) {
) : null}
<PopupTrigger contentRef={popupContentRef}>
<button className="remove-media">DELETE MEDIA</button>
<button className="remove-media">{translateString("DELETE MEDIA")}</button>
</PopupTrigger>
<PopupContent contentRef={popupContentRef}>

View File

@ -4,6 +4,7 @@ import { PageStore, MediaPageStore } from '../../utils/stores/';
import { MemberContext, PlaylistsContext } from '../../utils/contexts/';
import { MediaLikeIcon, MediaDislikeIcon, OtherMediaDownloadLink, VideoMediaDownloadLink, MediaSaveButton, MediaShareButton, MediaMoreOptionsIcon } from '../media-actions/';
import ViewerInfoTitleBanner from './ViewerInfoTitleBanner';
import { translateString } from '../../utils/helpers/';
export default class ViewerInfoVideoTitleBanner extends ViewerInfoTitleBanner {
render() {
@ -56,7 +57,7 @@ export default class ViewerInfoVideoTitleBanner extends ViewerInfoTitleBanner {
{displayViews ? (
<div className="media-views">
{formatViewsNumber(this.props.views, true)} {1 >= this.props.views ? 'view' : 'views'}
{formatViewsNumber(this.props.views, true)} {1 >= this.props.views ? translateString('view') : translateString('views')}
</div>
) : null}

View File

@ -4,6 +4,7 @@ import { PageStore } from '../../../utils/stores/';
import { HeaderConsumer, MemberConsumer, LinksConsumer } from '../../../utils/contexts/';
import { CircleIconButton, MaterialIcon, NavigationContentApp, NavigationMenuList, PopupTop, PopupMain, UserThumbnail } from '../../_shared';
import { HeaderThemeSwitcher } from './HeaderThemeSwitcher';
import { translateString } from '../../../utils/helpers/';
function headerPopupPages(user, popupNavItems, hasHeaderThemeSwitcher) {
const pages = {
@ -95,9 +96,9 @@ function LoginButton({ user, link, hasHeaderThemeSwitcher }) {
className={
'button-link sign-in' + (hasHeaderThemeSwitcher ? ' hidden-only-in-small' : ' hidden-only-in-extra-small')
}
title="Sign in"
title={translateString('Sign in')}
>
Sign in
{translateString('Sign in')}
</a>
</div>
) : null;
@ -112,9 +113,9 @@ function RegisterButton({ user, link, hasHeaderThemeSwitcher }) {
'button-link register-link' +
(hasHeaderThemeSwitcher ? ' hidden-only-in-small' : ' hidden-only-in-extra-small')
}
title="Register"
title={translateString('Register')}
>
Register
{translateString('Register')}
</a>
</div>
) : null;

View File

@ -4,6 +4,7 @@ import { LinksContext } from '../../../utils/contexts/';
import { PageStore, SearchFieldStore } from '../../../utils/stores/';
import { SearchFieldActions } from '../../../utils/actions/';
import { MaterialIcon, PopupMain } from '../../_shared';
import { translateString } from '../../../utils/helpers/';
import './SearchField.scss';
@ -296,7 +297,7 @@ export function SearchField(props) {
<input
ref={searchInputRef}
type="text"
placeholder="Search"
placeholder={translateString("Search")}
aria-label="Search"
name="q"
value={queryVal}

View File

@ -4,6 +4,7 @@ import { useUser } from '../../../utils/hooks/';
import { PageStore } from '../../../utils/stores/';
import { LinksContext, SidebarContext } from '../../../utils/contexts/';
import { NavigationMenuList } from '../../_shared';
import { translateString } from '../../../utils/helpers/';
export function SidebarNavigationMenu() {
const { userCan, isAnonymous, pages: userPages } = useUser();
@ -40,7 +41,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.home,
icon: 'home',
text: 'Home',
text: translateString('Home'),
className: 'nav-item-home',
});
}
@ -49,7 +50,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.featured,
icon: 'star',
text: PageStore.get('config-enabled').pages.featured.title,
text: translateString('Featured'),
className: 'nav-item-featured',
});
}
@ -61,7 +62,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.recommended,
icon: 'done_outline',
text: PageStore.get('config-enabled').pages.recommended.title,
text: translateString("Recommended"),
className: 'nav-item-recommended',
});
}
@ -70,7 +71,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.latest,
icon: 'new_releases',
text: PageStore.get('config-enabled').pages.latest.title,
text: translateString("Latest"),
className: 'nav-item-latest',
});
}
@ -83,7 +84,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.archive.tags,
icon: 'local_offer',
text: PageStore.get('config-enabled').taxonomies.tags.title,
text: translateString("Tags"),
className: 'nav-item-tags',
});
}
@ -96,7 +97,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.archive.categories,
icon: 'list_alt',
text: PageStore.get('config-enabled').taxonomies.categories.title,
text: translateString("Categories"),
className: 'nav-item-categories',
});
}
@ -105,7 +106,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.members,
icon: 'people',
text: PageStore.get('config-enabled').pages.members.title,
text: translateString("Members"),
className: 'nav-item-members',
});
}
@ -132,7 +133,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.user.addMedia,
icon: 'video_call',
text: 'Upload media',
text: translateString("Upload"),
className: 'nav-item-upload-media',
});
@ -140,7 +141,7 @@ export function SidebarNavigationMenu() {
items.push({
link: userPages.media,
icon: 'video_library',
text: 'My media',
text: translateString("My media"),
className: 'nav-item-my-media',
});
}
@ -150,7 +151,7 @@ export function SidebarNavigationMenu() {
items.push({
link: userPages.playlists,
icon: 'playlist_play',
text: 'My playlists',
text: translateString("My playlists"),
className: 'nav-item-my-playlists',
});
}
@ -166,7 +167,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.user.history,
icon: 'history',
text: PageStore.get('config-enabled').pages.history.title,
text: translateString("History"),
className: 'nav-item-history',
});
}
@ -179,7 +180,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.user.liked,
icon: 'thumb_up',
text: PageStore.get('config-enabled').pages.liked.title,
text: translateString("Liked media"),
className: 'nav-item-liked',
});
}
@ -188,7 +189,35 @@ export function SidebarNavigationMenu() {
}
function CustomMenuSection() {
const items = PageStore.get('config-contents').sidebar.navMenu.items;
const items = [];
items.push({
link: '/about',
icon: 'contact_support',
text: translateString("About"),
className: 'nav-item-about',
});
items.push({
link: '/tos',
icon: 'description',
text: translateString("Terms"),
className: 'nav-item-terms',
});
items.push({
link: '/contact',
icon: 'alternate_email',
text: translateString("Contact"),
className: 'nav-item-contact',
});
items.push({
link: '/setlanguage',
icon: 'language',
text: translateString("Language"),
className: 'nav-item-language',
});
return items.length ? <NavigationMenuList key="custom" items={formatItems(items)} /> : null;
}
@ -200,7 +229,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.manage.media,
icon: 'miscellaneous_services',
text: 'Manage media',
text: translateString("Manage media"),
className: 'nav-item-manage-media',
});
}
@ -209,7 +238,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.manage.users,
icon: 'miscellaneous_services',
text: 'Manage users',
text: translateString("Manage users"),
className: 'nav-item-manage-users',
});
}
@ -218,7 +247,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.manage.comments,
icon: 'miscellaneous_services',
text: 'Manage comments',
text: translateString("Manage comments"),
className: 'nav-item-manage-comments',
});
}

View File

@ -6,6 +6,7 @@ import { PageStore, ProfilePageStore } from '../../utils/stores/';
import { PageActions, ProfilePageActions } from '../../utils/actions/';
import { CircleIconButton, PopupMain } from '../_shared';
import ItemsInlineSlider from '../item-list/includes/itemLists/ItemsInlineSlider';
import { translateString } from '../../utils/helpers/';
class ProfileSearchBar extends React.PureComponent {
constructor(props) {
@ -315,13 +316,13 @@ class NavMenuInlineTabs extends React.PureComponent {
<InlineTab
id="about"
isActive={'about' === this.props.type}
label={'About' + (this.userIsAuthor ? ' Me' : '')}
label={translateString('About')}
link={LinksContext._currentValue.profile.about}
/>
<InlineTab
id="media"
isActive={'media' === this.props.type}
label={(this.userIsAuthor ? 'My ' : '') + 'Media'}
label={translateString('Media')}
link={LinksContext._currentValue.profile.media}
/>
@ -329,7 +330,7 @@ class NavMenuInlineTabs extends React.PureComponent {
<InlineTab
id="playlists"
isActive={'playlists' === this.props.type}
label={(this.userIsAuthor ? 'My ' : '') + 'Playlists'}
label={translateString('Playlists')}
link={LinksContext._currentValue.profile.playlists}
/>
) : null}

View File

@ -3,13 +3,14 @@ import { ApiUrlConsumer } from '../utils/contexts/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface CategoriesPageProps {
id?: string;
title?: string;
}
export const CategoriesPage: React.FC<CategoriesPageProps> = ({ id = 'categories', title = 'Categories' }) => (
export const CategoriesPage: React.FC<CategoriesPageProps> = ({ id = 'categories', title = translateString('Categories') }) => (
<Page id={id}>
<ApiUrlConsumer>
{(apiUrl) => (

View File

@ -4,6 +4,7 @@ import { PageStore } from '../utils/stores/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface FeaturedMediaPageProps {
id?: string;
@ -12,7 +13,7 @@ interface FeaturedMediaPageProps {
export const FeaturedMediaPage: React.FC<FeaturedMediaPageProps> = ({
id = 'featured-media',
title = PageStore.get('config-enabled').pages.featured.title,
title = translateString('Featured'),
}) => (
<Page id={id}>
<ApiUrlConsumer>

View File

@ -7,6 +7,7 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { ProfileHistoryPage } from './ProfileHistoryPage';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
declare global {
interface Window {
@ -21,7 +22,7 @@ interface AnonymousHistoryPageProps {
export const AnonymousHistoryPage: React.FC<AnonymousHistoryPageProps> = ({
id = 'history-media',
title = PageStore.get('config-enabled').pages.history.title,
title = translateString('History'),
}) => {
const [resultsCount, setResultsCount] = useState<number | null>(null);

View File

@ -6,6 +6,7 @@ import { MediaMultiListWrapper } from '../components/MediaMultiListWrapper';
import { ItemListAsync } from '../components/item-list/ItemListAsync.jsx';
import { InlineSliderItemListAsync } from '../components/item-list/InlineSliderItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
const EmptyMedia: React.FC = ({}) => {
return (
@ -35,9 +36,12 @@ interface HomePageProps {
export const HomePage: React.FC<HomePageProps> = ({
id = 'home',
featured_title = PageStore.get('config-options').pages.home.sections.featured.title,
recommended_title = PageStore.get('config-options').pages.home.sections.recommended.title,
latest_title = PageStore.get('config-options').pages.home.sections.latest.title,
//featured_title = PageStore.get('config-options').pages.home.sections.featured.title,
//recommended_title = PageStore.get('config-options').pages.home.sections.recommended.title,
//latest_title = PageStore.get('config-options').pages.home.sections.latest.title,
featured_title = translateString('Featured'),
recommended_title = translateString('Recommended'),
latest_title = translateString('Latest'),
latest_view_all_link = false,
featured_view_all_link = true,
recommended_view_all_link = true,

View File

@ -4,6 +4,7 @@ import { PageStore } from '../utils/stores/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface LatestMediaPageProps {
id?: string;
@ -12,7 +13,7 @@ interface LatestMediaPageProps {
export const LatestMediaPage: React.FC<LatestMediaPageProps> = ({
id = 'latest-media',
title = PageStore.get('config-enabled').pages.latest.title,
title = translateString('Recent uploads'),
}) => (
<Page id={id}>
<ApiUrlConsumer>

View File

@ -7,6 +7,7 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
import { ProfileLikedPage } from './ProfileLikedPage';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
declare global {
interface Window {
@ -21,7 +22,7 @@ interface AnonymousLikedMediaPageProps {
export const AnonymousLikedMediaPage: React.FC<AnonymousLikedMediaPageProps> = ({
id = 'liked-media',
title = PageStore.get('config-enabled').pages.liked.title,
title = translateString('Liked media'),
}) => {
const [resultsCount, setResultsCount] = useState<number | null>(null);

View File

@ -4,6 +4,7 @@ import { PageStore } from '../utils/stores/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface RecommendedMediaPageProps {
id?: string;
@ -12,7 +13,7 @@ interface RecommendedMediaPageProps {
export const RecommendedMediaPage: React.FC<RecommendedMediaPageProps> = ({
id = 'recommended-media',
title = PageStore.get('config-enabled').pages.recommended.title,
title = translateString('Recommended'),
}) => (
<Page id={id}>
<ApiUrlConsumer>

View File

@ -7,6 +7,7 @@ import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListA
import { SearchMediaFiltersRow } from '../components/search-filters/SearchMediaFiltersRow';
import { SearchResultsFilters } from '../components/search-filters/SearchResultsFilters';
import { Page } from './_Page';
import { translateString } from '../utils/helpers/';
export class SearchPage extends Page {
constructor(props) {
@ -114,13 +115,13 @@ export class SearchPage extends Page {
} else {
if (this.state.searchCategories) {
title = null === this.state.resultsCount || 0 === this.state.resultsCount ? 'No' : this.state.resultsCount;
title += ' media in category "' + this.state.searchCategories + '"';
title += ' ' + translateString('media in category') + ' "' + this.state.searchCategories + '"';
} else if (this.state.searchTags) {
title = null === this.state.resultsCount || 0 === this.state.resultsCount ? 'No' : this.state.resultsCount;
title += ' media in tag "' + this.state.searchTags + '"';
title += ' ' + translateString('media in tag') + ' "' + this.state.searchTags + '"';
} else {
if (null === this.state.resultsCount || 0 === this.state.resultsCount) {
title = 'No results for "' + this.state.searchQuery + '"';
title = translateString('No results for') + ' "' + this.state.searchQuery + '"';
} else {
title =
this.state.resultsCount +

View File

@ -3,13 +3,14 @@ import { ApiUrlConsumer } from '../utils/contexts/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface TagsPageProps {
id?: string;
title?: string;
}
export const TagsPage: React.FC<TagsPageProps> = ({ id = 'tags', title = 'Tags' }) => (
export const TagsPage: React.FC<TagsPageProps> = ({ id = 'tags', title = translateString('Tags') }) => (
<Page id={id}>
<ApiUrlConsumer>
{(apiUrl) => (

View File

@ -1,4 +1,5 @@
import { addClassname, removeClassname } from '../helpers/';
import { translateString } from '../../utils/helpers/';
export function UpNextLoaderView(nextItemData) {
var timerTimeout;
@ -39,7 +40,7 @@ export function UpNextLoaderView(nextItemData) {
domElems.nextMediaTitle.setAttribute('class', 'next-media-title');
domElems.nextMediaAuthor.setAttribute('class', 'next-media-author');
domElems.upNextLabel.innerHTML = 'Up Next';
domElems.upNextLabel.innerHTML = translateString('Up Next');
domElems.nextMediaTitle.innerHTML = nextItemData.title;
domElems.nextMediaAuthor.innerHTML = nextItemData.author_name;

View File

@ -1,5 +1,6 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
import { translateString } from '../../utils/helpers/';
const config = mediacmsConfig(window.MediaCMS);
@ -17,7 +18,7 @@ function popupTopNavItems() {
items.push({
link: links.user.addMedia,
icon: 'video_call',
text: 'Upload media',
text: translateString('Upload media'),
itemAttr: {
className: 'visible-only-in-small',
},
@ -27,7 +28,7 @@ function popupTopNavItems() {
items.push({
link: user.pages.media,
icon: 'video_library',
text: 'My media',
text: translateString('My media'),
});
}
}
@ -35,7 +36,7 @@ function popupTopNavItems() {
items.push({
link: links.signout,
icon: 'exit_to_app',
text: 'Sign out',
text: translateString('Sign out'),
});
}
@ -64,7 +65,7 @@ function popupMiddleNavItems() {
itemType: 'link',
icon: 'login',
iconPos: 'left',
text: 'Sign in',
text: translateString('Sign in'),
link: links.signin,
linkAttr: {
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
@ -77,7 +78,7 @@ function popupMiddleNavItems() {
itemType: 'link',
icon: 'person_add',
iconPos: 'left',
text: 'Register',
text: translateString('Register'),
link: links.register,
linkAttr: {
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
@ -88,14 +89,14 @@ function popupMiddleNavItems() {
items.push({
link: links.user.editProfile,
icon: 'brush',
text: 'Edit profile',
text: translateString('Edit profile'),
});
if (user.can.changePassword) {
items.push({
link: links.changePassword,
icon: 'lock',
text: 'Change password',
text: translateString('Change password'),
});
}
}

View File

@ -12,3 +12,5 @@ export * from './propTypeFilters';
export { default as publishedOnDate } from './publishedOnDate';
export * from './quickSort';
export * from './requests';
export { translateString } from './translate';
export { replaceString } from './replacementStrings';

View File

@ -0,0 +1,8 @@
// check templates/config/installation/translations.html for more
export function replaceString(string) {
for (const key in window.REPLACEMENTS) {
string = string.replace(key, window.REPLACEMENTS[key]);
}
return string;
}

View File

@ -0,0 +1,9 @@
// check templates/config/installation/translations.html for more
export function translateString(string) {
if (window.TRANSLATION && window.TRANSLATION[string]) {
return window.TRANSLATION[string];
} else {
return string;
}
}

View File

@ -1,5 +1,6 @@
import React, { useEffect, useRef } from 'react';
import { useItemList } from './useItemList';
import { translateString } from '../../utils/helpers/';
export function useItemListSync(props) {
const itemsListRef = useRef(null);
@ -32,7 +33,7 @@ export function useItemListSync(props) {
return 1 > listHandler.totalPages() || listHandler.loadedAllItems() ? null : (
<button className="load-more" onClick={onClickLoadMore}>
SHOW MORE
{translateString("SHOW MORE")}
</button>
);
}

View File

@ -10,6 +10,7 @@ import {
MediaItemEditLink,
} from '../../components/list-item/includes/items';
import { useItem } from './useItem';
import { replaceString } from '../../utils/helpers/';
export function itemClassname(defaultClassname, inheritedClassname, isActiveInPlaylistPlayback) {
let classname = defaultClassname;
@ -56,7 +57,7 @@ export function useMediaItem(props) {
return null;
}
const publishDate = format(new Date(props.publish_date));
const publishDate = replaceString(format(new Date(props.publish_date)));
const publishDateTime =
'string' === typeof props.publish_date
? Date.parse(props.publish_date)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,10 @@
{% extends "base.html" %}
{% load i18n %}
{% block headtitle %}About - {{PORTAL_NAME}}{% endblock headtitle %}
{% block headermeta %}
{% load custom_filters %}
<meta property="og:title" content="About - {{PORTAL_NAME}}">
<meta property="og:type" content="website">
<meta property="og:description" content="">
@ -38,10 +39,13 @@
{% endblock headermeta %}
{% block innercontent %}
{% get_current_language as LANGUAGE_CODE %}
<div class="custom-page-wrapper">
<h2>About</h2>
<h2>{{ "About" | custom_translate:LANGUAGE_CODE}}</h2>
<hr/>
<p><a href="https://mediacms.io">MediaCMS</a> is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media.</p>
<p><a href="https://mediacms.io">MediaCMS</a> {{ "is a modern, fully featured open source video and media CMS. It is developed to meet the needs of modern web platforms for viewing and sharing media" | custom_translate:LANGUAGE_CODE}}.</p>
</div>
{% endblock %}

View File

@ -0,0 +1,68 @@
{% extends "base.html" %}
{% load i18n %}
{% load custom_filters %}
{% block headtitle %}About - {{PORTAL_NAME}}{% endblock headtitle %}
{% block headermeta %}
<meta property="og:title" content="About - {{PORTAL_NAME}}">
<meta property="og:type" content="website">
<meta property="og:description" content="">
<meta name="twitter:card" content="summary">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "{{PORTAL_NAME}}",
"item": {
"@type": "WebPage",
"@id": "{{FRONTEND_HOST}}"
}
},
{
"@type": "ListItem",
"position": 2,
"name": "About",
"item": {
"@type": "AboutPage",
"@id": "{{FRONTEND_HOST}}/about"
}
}]
}
</script>
{% endblock headermeta %}
{% block innercontent %}
<div class="custom-page-wrapper">
{% get_current_language as LANGUAGE_CODE %}
<h1>{{"Change Language"| custom_translate:LANGUAGE_CODE}}</h1>
<hr/>
<h2>{{"Select"| custom_translate:LANGUAGE_CODE}}</h2>
<p>
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
<input name="next" type="hidden" value="/">
<select name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value={{"Go"| custom_translate:LANGUAGE_CODE}}>
</form>
</p>
</div>
{% endblock %}

View File

@ -1,10 +1,11 @@
<script type="text/javascript">
var MediaCMS = {
{% if media %}mediaId: "{{media}}", {% endif %}
{% if user %}profileId: "{{user.username}}", {% endif %}
};
{% include "config/core/api.html" %}
{% include "config/core/url.html" %}
{% include "config/core/user.html" %}
@ -14,6 +15,8 @@
{% include "config/installation/pages.html" %}
{% include "config/installation/site.html" %}
{% include "config/installation/translations.html" %}
window.MediaCMS = MediaCMS;
</script>

View File

@ -0,0 +1,14 @@
// These are the translations that will be used in frontend/src using the helper function
// translateString (frontend/src/static/js/utils/helpers/translate.js)
// They are fetched from the backend, and specifically files/frontend_translations
// The Django backend is passing dictionary FRONTEND_TRANSLATIONS.
// This contains key values where keys do not have a space
// TRANSLATIONS object will be availaible as window.TRANSLATIONS
// IMPORTANT: If you are starting the frontend app (localhost:8088), you are not getting at this
// POINT, so there are not translations. Translations can only be available and tested on the Django app
// and templates, that are loading React as well
window.TRANSLATION = {{ TRANSLATION|safe }};;
window.REPLACEMENTS = {{ REPLACEMENTS|safe }};;