Menulis plugin VLC untuk belajar bahasa Inggris

gambar

Pada artikel ini saya akan berbicara tentang cara menulis plugin dalam C untuk pemutar media VLC. Saya menulis plugin saya untuk menyederhanakan menonton acara TV dan film dalam bahasa Inggris. Gagasan membuat plugin ini dijelaskan di bagian Ide dan Menemukan solusi . Rincian teknis penerapan plugin diberikan di bagian Hello World plugin dan Implementasi . Apa yang terjadi pada akhirnya dan bagaimana menggunakannya dapat ditemukan di bagian terakhir, Hasil .

Kode sumber untuk proyek tersedia di GitHub .

Ide


Gagasan belajar bahasa asing sambil menonton serial favorit saya bukanlah hal baru, tetapi saya selalu memiliki masalah dengannya secara pribadi. Sangat sulit untuk menonton serial atau film ketika Anda tidak mengerti setengah dari apa yang mereka katakan. Tentu saja, Anda dapat mengaktifkan subtitle, tetapi jika kata atau ungkapan yang tidak dikenal ditemui dalam pidato, itu tidak akan menjadi lebih jelas bahwa itu akan diduplikasi oleh teks. Dan saya sama sekali tidak suka menonton serial dengan subtitle Rusia - otak beralih ke bahasa aslinya dan tidak lagi memahami bahasa asing. Saya membaca di suatu tempat bahwa pertama-tama Anda perlu menonton seri dalam bahasa Rusia, dan kemudian dalam aslinya. Tapi pendekatan ini juga tidak cocok untukku. Pertama, di mana mengambil begitu banyak waktu untuk menonton hal yang sama beberapa kali, dan kedua, menonton kedua kalinya tidak begitu menarik lagi - motivasi hilang.

Terlepas dari semua kesulitan menonton acara TV asing, saya dapat membaca dokumentasi teknis, artikel, dan buku dalam bahasa Inggris dengan cukup baik. Saya suka membaca buku pada pembaca elektronik Kindle, karena fungsi kamusnya keren, Anda dapat menemukan terjemahan kata yang tidak dikenal dengan satu sentuhan layar. Lebih mudah untuk membaca artikel dan situs berbahasa Inggris dengan memasang ekstensi khusus untuk terjemahan di browser - Saya menggunakan ekstensi Yandex.Translation . Pendekatan ini memungkinkan Anda untuk membaca dan memahami teks-teks bahasa Inggris, tanpa banyak gangguan untuk mencari kata-kata yang tidak dikenal.

Saya pikir, mengapa tidak menerapkan pendekatan yang sama untuk menonton acara TV - kita menghidupkan seri dalam bahasa Inggris segera setelah frasa yang tidak dapat dimengerti ditemukan, beralih ke trek audio Rusia dan mundur sedikit ke belakang. Selanjutnya, kami terus menonton serial dalam bahasa Inggris.

Cari solusinya


Faktanya, semua fungsi yang saya butuhkan sudah tersedia di banyak pemutar media populer. Satu-satunya hal yang saya ingin beralih trek audio dan memundurkan video beberapa detik yang lalu dengan mengklik tombol. Akan lebih bagus jika, setelah menerjemahkan sebuah fragmen yang tidak dapat dipahami, media player itu sendiri mengganti trek audio kembali ke bahasa Inggris. Yah, alangkah baiknya untuk dapat mengulangi fragmen yang diterjemahkan sebelumnya dengan trek bahasa Inggris.

Artinya, saya membutuhkan media player yang dapat Anda gunakan untuk menulis plugin. Ini juga diinginkan bahwa itu adalah cross-platform, karena saya menggunakan PC di bawah Windows dan laptop di Linux. Pilihan saya segera jatuh pada VLC. Pada habr saya bahkan menemukan artikel di mana @Idunno memberitahu bagaimana menulis ekstensi VLC pada LUA. Ngomong-ngomong, dia juga menulis ekstensi ini untuk belajar bahasa Inggris) Sayangnya, ekstensi ini tidak berfungsi dalam versi terbaru VLC (lebih tua dari 2.0.5). Karena operasi yang tidak stabil, kemampuan untuk menambahkan fungsi panggilan balik yang memungkinkan untuk memproses acara keyboard dalam ekstensi LUA dihapus dari LUA API. Di README , tautan ke milis pengembang VLC yang membahas masalah ini mengarah ke ekstensi di GitHub @Idunno .

Jadi, untuk mengimplementasikan ide saya, ekstensi ke LUA tidak berfungsi, Anda perlu menulis sebuah plugin dalam C. Dan meskipun saya menulis sesuatu dalam C terakhir kali sekitar 7 tahun yang lalu, kembali ke universitas, saya memutuskan untuk mencobanya.

Halo plugin dunia


Perlu dicatat bahwa pemutar media VLC memiliki dokumentasi yang cukup bagus. Saya belajar dari itu bahwa pengembangan media player menggunakan pendekatan modular. VLC terdiri dari beberapa modul independen yang mengimplementasikan fungsi tertentu, dan kernel ( libVLCCore ), yang mengelola modul-modul ini. Ada dua jenis modul: internal ( in-tree ) dan eksternal ( out-of-tree ). Kode sumber modul internal disimpan dalam satu repositori dengan kode kernel. Modul eksternal dikembangkan dan dirakit secara terpisah dari pemutar media VLC. Sebenarnya, yang terakhir adalah apa yang disebut plugin.

Dokumentasi juga memiliki artikel tentang cara menulis plug-in Anda (modul) dalam C. Artikel ini memberikan kode sumber plug-in sederhana yang, ketika VLC dimulai, menampilkan pesan selamat datang " Halo, <nama> " ke konsol (nilai <nama> diambil dari pengaturan plugin). Berjalan sedikit di depan, saya akan mengatakan bahwa dalam contoh di atas, tambahkan baris berikut setelah set_category(CAT_INTERFACE) :

 set_subcategory( SUBCAT_INTERFACE_CONTROL ) 

Nah, yang tersisa hanyalah merakit plug-in dan menguji operasinya. Ada juga instruksi untuk membangun plugin eksternal. Di sini ada baiknya memperhatikan bagian Internasionalisasi , yang menggambarkan bagaimana lokalisasi bekerja di VLC. Singkatnya, untuk plug-in eksternal Anda perlu mendefinisikan macro N_() , _() :

 #define DOMAIN "vlc-myplugin" #define _(str) dgettext(DOMAIN, str) #define N_(str) (str) 

Untuk perakitan, diusulkan untuk menggunakan Makefile tua yang baik atau Autotools. Saya memutuskan untuk pergi dengan cara yang sederhana dan memilih Makefile. Di Makefile Anda harus ingat untuk mendefinisikan variabel MODULE_STRING - ini adalah pengidentifikasi plugin kami. Saya juga sedikit mengubah pekerjaan dengan direktori - sekarang mereka didefinisikan melalui pkg-config . Hasilnya adalah file-file berikut:

hello.c
 /** * @file hello.c * @brief Hello world interface VLC module example */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #define DOMAIN "vlc-myplugin" #define _(str) dgettext(DOMAIN, str) #define N_(str) (str) #include <stdlib.h> /* VLC core API headers */ #include <vlc_common.h> #include <vlc_plugin.h> #include <vlc_interface.h> /* Forward declarations */ static int Open(vlc_object_t *); static void Close(vlc_object_t *); /* Module descriptor */ vlc_module_begin() set_shortname(N_("Hello")) set_description(N_("Hello interface")) set_capability("interface", 0) set_callbacks(Open, Close) set_category(CAT_INTERFACE) set_subcategory( SUBCAT_INTERFACE_CONTROL ) add_string("hello-who", "world", "Target", "Whom to say hello to.", false) vlc_module_end () /* Internal state for an instance of the module */ struct intf_sys_t { char *who; }; /** * Starts our example interface. */ static int Open(vlc_object_t *obj) { intf_thread_t *intf = (intf_thread_t *)obj; /* Allocate internal state */ intf_sys_t *sys = malloc(sizeof (*sys)); if (unlikely(sys == NULL)) return VLC_ENOMEM; intf->p_sys = sys; /* Read settings */ char *who = var_InheritString(intf, "hello-who"); if (who == NULL) { msg_Err(intf, "Nobody to say hello to!"); goto error; } sys->who = who; msg_Info(intf, "Hello %s!", who); return VLC_SUCCESS; error: free(sys); return VLC_EGENERIC; } /** * Stops the interface. */ static void Close(vlc_object_t *obj) { intf_thread_t *intf = (intf_thread_t *)obj; intf_sys_t *sys = intf->p_sys; msg_Info(intf, "Good bye %s!", sys->who); /* Free internal state */ free(sys->who); free(sys); } 

Makefile
 LD = ld CC = cc PKG_CONFIG = pkg-config INSTALL = install CFLAGS = -g -O2 -Wall -Wextra LDFLAGS = LIBS = VLC_PLUGIN_CFLAGS := $(shell $(PKG_CONFIG) --cflags vlc-plugin) VLC_PLUGIN_LIBS := $(shell $(PKG_CONFIG) --libs vlc-plugin) VLC_PLUGIN_DIR := $(shell $(PKG_CONFIG) --variable=pluginsdir vlc-plugin) plugindir = $(VLC_PLUGIN_DIR)/misc override CC += -std=gnu99 override CPPFLAGS += -DPIC -I. -Isrc override CFLAGS += -fPIC override LDFLAGS += -Wl,-no-undefined,-z,defs override CPPFLAGS += -DMODULE_STRING=\"hello\" override CFLAGS += $(VLC_PLUGIN_CFLAGS) override LIBS += $(VLC_PLUGIN_LIBS) all: libhello_plugin.so install: all mkdir -p -- $(DESTDIR)$(plugindir) $(INSTALL) --mode 0755 libhello_plugin.so $(DESTDIR)$(plugindir) install-strip: $(MAKE) install INSTALL="$(INSTALL) -s" uninstall: rm -f $(plugindir)/libhello_plugin.so clean: rm -f -- libhello_plugin.so src/*.o mostlyclean: clean SOURCES = hello.c $(SOURCES:%.c=src/%.o): $(SOURCES:%.c=src/%.c) libhello_plugin.so: $(SOURCES:%.c=src/%.o) $(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS) .PHONY: all install install-strip uninstall clean mostlyclean 

Cara termudah untuk membangun plugin untuk Linux. Untuk melakukan ini, Anda perlu menginstal, pada kenyataannya, VLC media player itu sendiri, serta file dan alat yang diperlukan untuk membangun plug-in. Di Debian / Ubuntu, ini bisa dilakukan dengan perintah berikut:

 sudo apt-get install vlc libvlc-dev libvlccore-dev gcc make pkg-config 

Sebenarnya, semuanya sudah siap, kami mengumpulkan dan menginstal plugin kami menggunakan perintah:

 sudo make install 

Untuk menguji plugin, jalankan VLC juga dari konsol:

 vlc 

Sayangnya, kami tidak melihat " Hello world ". Masalahnya adalah bahwa plugin harus diaktifkan terlebih dahulu. Untuk melakukan ini, buka pengaturan ( Alat > Preferensi ), beralih ke tampilan lanjutan (pilih Semua di grup Tampilkan pengaturan ) dan temukan di bagan di panel kiri Antarmuka > Kontrol antarmuka - centang kotak di sebelah plugin Hello interface kami.



Kami menyimpan pengaturan dan memulai kembali VLC.



Buat plugin untuk Windows


Dengan Windows, segalanya menjadi sedikit lebih rumit. Untuk membangun plugin, Anda perlu mengunduh SDK, yang berisi perpustakaan, header dan file konfigurasi VLC. Sebelumnya, SDK adalah bagian dari rakitan VLC biasa dan dapat ditemukan di folder instalasi program. Sekarang hadir sebagai unit pemutar media yang terpisah. Misalnya, untuk VLC versi 3.0.8, majelis ini dapat diunduh di ftp://ftp.videolan.org/pub/videolan/vlc/3.0.8/win64/vlc-3.0.8-win64.7z (penting untuk mengunduh 7z -ber arsip).

Salin konten arsip ke folder, misalnya, ke C: \ Projects . Selain sdk, arsip juga berisi media player itu sendiri, yang dapat digunakan untuk menguji dan men-debug plug-in.

Agar Makefile kami dapat digunakan untuk membangun dan menginstal plugin, Anda perlu memperbaiki file C: \ Projects \ vlc-3.0.8 \ sdk \ lib \ pkgconfig \ vlc-plugin.pc , yang menunjukkan jalur yang benar ke folder sdk di awalan dan variabel pluginsdir dan plugin masing-masing:

 prefix=/c/Projects/vlc-3.0.8/sdk pluginsdir=/c/Projects/vlc-3.0.8/plugins 

Untuk membangun di bawah Windows, kita juga perlu menginstal kompiler dan utilitas lain. Semua perangkat lunak yang diperlukan dapat diperoleh dengan menginstal lingkungan MSYS2 . Situs web proyek memiliki petunjuk instalasi yang terperinci. Singkatnya, segera setelah instalasi Anda harus membuka konsol ( C: \ msys64 \ msys2.exe ) dan memperbarui paket MSYS2 menggunakan perintah:

 pacman -Syu 

Selanjutnya, tutup jendela terminal MSYS2, lalu buka lagi dan jalankan perintah

 pacman -Su 

Setelah memperbarui semua paket, Anda perlu menginstal rantai alat:

 pacman -S base-devel mingw-w64-x86_64-toolchain 

Sekarang semua paket yang diperlukan sudah diinstal, Anda dapat mulai membangun plugin. Saya memodifikasi Makefile sedikit sehingga bisa membangun plugin baik di Linux maupun di Windows. Selain itu, saya harus menghapus beberapa parameter build MinGW yang tidak didukung, akibatnya Makefile mulai terlihat seperti ini:

Makefile untuk Windows
 LD = ld CC = cc PKG_CONFIG = pkg-config INSTALL = install CFLAGS = -g -O2 -Wall -Wextra LDFLAGS = LIBS = VLC_PLUGIN_CFLAGS := $(shell $(PKG_CONFIG) --cflags vlc-plugin) VLC_PLUGIN_LIBS := $(shell $(PKG_CONFIG) --libs vlc-plugin) VLC_PLUGIN_DIR := $(shell $(PKG_CONFIG) --variable=pluginsdir vlc-plugin) plugindir = $(VLC_PLUGIN_DIR)/misc override CC += -std=gnu99 override CPPFLAGS += -DPIC -I. -Isrc override CFLAGS += -fPIC override LDFLAGS += -Wl,-no-undefined override CPPFLAGS += -DMODULE_STRING=\"hello\" override CFLAGS += $(VLC_PLUGIN_CFLAGS) override LIBS += $(VLC_PLUGIN_LIBS) SUFFIX := so ifeq ($(OS),Windows_NT) SUFFIX := dll endif all: libhello_plugin.$(SUFFIX) install: all mkdir -p -- $(DESTDIR)$(plugindir) $(INSTALL) --mode 0755 libhello_plugin.$(SUFFIX) $(DESTDIR)$(plugindir) install-strip: $(MAKE) install INSTALL="$(INSTALL) -s" uninstall: rm -f $(plugindir)/libhello_plugin.$(SUFFIX) clean: rm -f -- libhello_plugin.$(SUFFIX) src/*.o mostlyclean: clean SOURCES = hello.c $(SOURCES:%.c=src/%.o): $(SOURCES:%.c=src/%.c) libhello_plugin.$(SUFFIX): $(SOURCES:%.c=src/%.o) $(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS) .PHONY: all install install-strip uninstall clean mostlyclean 

Karena MSYS2 tidak tahu apa-apa tentang SDK kami untuk VLC, Anda perlu menambahkan path ke folder pkgconfig dari SDK ini ke variabel lingkungan PKG_CONFIG_PATH . Buka konsol MinGW ( C: \ msys64 \ mingw64.exec ) dan jalankan perintah:

 export PKG_CONFIG_PATH=/c/projects/vlc-3.0.8/sdk/lib/pkgconfig:$PKG_CONFIG_PATH make install 

Untuk menguji plugin, jalankan VLC juga dari konsol:

 /c/projects/vlc-3.0.8/vlc 

Seperti halnya Linux, buka pengaturan dan nyalakan plugin kami. Kami menyimpan pengaturan dan memulai kembali VLC.

Implementasi plugin


Untuk menerapkan plugin saya, saya perlu memahami cara mengontrol pemutar media (mengubah trek audio, mundur) dan bagaimana menangani peristiwa keystroke keyboard. Untuk memahami semua ini, saya beralih ke dokumentasi . Juga di Internet saya menemukan beberapa artikel menarik yang menjelaskan arsitektur pemutar media: Arsitektur kerangka media VLC dan pemutar media VLC Dokumentasi API .

VLC terdiri dari sejumlah besar modul independen (400+). Setiap modul harus memberikan informasi tentang jenis fungsionalitas yang diterapkannya, serta fungsi inisialisasi / finalisasi. Informasi ini dijelaskan dalam blok vlc_module_begin () - vlc_module_end () menggunakan makro set_capability () dan set_callbacks () . Fungsi inisialisasi / finalisasi modul (biasanya disebut Buka dan Tutup ) memiliki tanda tangan berikut:

 static int Open(vlc_object_t *) static void Close(vlc_object_t *) 

vlc_object_t adalah tipe dasar untuk mewakili data dalam VLC, yang darinya semua orang lain diwarisi (lihat artikel Object_Management ). Pointer ke vlc_object_t harus dilemparkan ke tipe data tertentu sesuai dengan fungsionalitas yang diterapkan modul. Untuk mengontrol pemutar media, saya mengatur nilai antarmuka di makro set_capability () . Dengan demikian, dalam fungsi Buka dan Tutup , saya harus menggunakan vlc_object_t ke intf_thread_t .

Interaksi antara modul didasarkan pada pola desain pengamat . VLC menyediakan mekanisme "variabel objek" (lihat Variabel ), yang dengannya Anda dapat menambahkan variabel ke instance tipe vlc_object_t (dan turunannya). Modul dapat bertukar data melalui variabel-variabel ini. Anda juga dapat melampirkan fungsi panggilan balik ke variabel, yang akan dipanggil ketika nilai variabel ini berubah.

Sebagai contoh, pertimbangkan modul Hotkeys ( modul / kontrol / hotkeys.c ), yang bertanggung jawab untuk menangani acara hotkey. Di fungsi Terbuka, fungsi callback ActionEvent digantung pada variabel aksi-kunci :

 var_AddCallback( p_intf->obj.libvlc, "key-action", ActionEvent, p_intf ); 

Pointer ke vlc_object_t , nama variabel, fungsi callback, dan pointer ke void diteruskan ke fungsi var_AddCallback untuk meneruskan data acak, yang kemudian diteruskan ke fungsi callback yang ditentukan. Tanda tangan dari fungsi panggilan balik ditunjukkan di bawah ini.

 static int ActionEvent(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *) 

Penunjuk ke vlc_object_t , nama variabel, nilai lama dan baru dari variabel ini (dalam hal ini, pengidentifikasi kombinasi hotkey yang ditekan dari tindakan), serta penunjuk ke data tambahan yang ditentukan saat menambahkan fungsi panggilan balik, diteruskan ke fungsi panggilan balik .

Pemrosesan langsung dari peristiwa hotkey dilakukan di fungsi PutAction , yang disebut di dalam fungsi callback ActionEvent . Fungsi PutAction menerima pengidentifikasi peristiwa menekan kombinasi tombol pintas ( i_action ) dan, dengan bantuan operator sakelar, melakukan tindakan yang sesuai.

Misalnya, acara mundur terkait dengan ACTIONID_JUMP_BACKWARD_SHORT . Untuk melakukan tindakan yang sesuai, interval mundur diambil dari pengaturan VLC (dari variabel short-jump-size ):

 mtime_t it = var_InheritInteger( p_input, varname ); 

Untuk memundurkan file yang sedang diputar, cukup atur variabel offset waktu ke nilai yang sesuai dengan waktu (dalam mikrodetik) yang digunakan untuk menggeser pemutaran:

 var_SetInteger( p_input, "time-offset", it * sign * CLOCK_FREQ ); 

Untuk maju cepat, Anda perlu menentukan nilai positif, untuk mundur cepat - negatif. Konstanta CLOCK_FREQ digunakan untuk mengonversi detik ke mikrodetik.

Demikian pula, trek audio berubah ( ACTIONID_AUDIO_TRACK acara). Hanya variabel audio yang bertanggung jawab untuk trek audio yang dapat menerima serangkaian nilai terbatas (sesuai dengan trek audio yang tersedia dalam file yang sedang diputar). Anda bisa mendapatkan daftar nilai yang mungkin dari suatu variabel menggunakan fungsi var_Change () :

 vlc_value_t list, list2; var_Change( p_input, "audio-es", VLC_VAR_GETCHOICES, &list, &list2 ); 

Selain daftar nilai, fungsi ini juga memungkinkan Anda untuk mendapatkan daftar deskripsi nilai-nilai ini (dalam hal ini, nama trek audio). Sekarang kita dapat mengubah trek audio menggunakan fungsi var_Set () :

 var_Set( p_input, "audio-es", list.p_list->p_values[i] ); 

Cara mengelola pemutar media tahu, tetap belajar bagaimana menangani acara keyboard. Sayangnya, saya tidak bisa menambahkan hotkey baru. Semua tombol pintas dikodekan dalam kode kernel VLC ( src / misc / actions.c ). Oleh karena itu, saya menambahkan handler untuk acara keystroke keyboard tingkat rendah, menggantung fungsi callback saya untuk mengubah variabel yang ditekan tombol :

 var_AddCallback( p_intf->obj.libvlc, "key-pressed", KeyboardEvent, p_intf ); 

Variabel yang ditekan tombol menyimpan kode karakter (dalam Unicode) yang sesuai dengan tombol terakhir yang ditekan. Misalnya, ketika Anda menekan tombol dengan angka "1" , variabel yang ditekan tombol akan diberi nilai 49 (0x00000031 dalam sistem angka ke-16). Anda dapat melihat kode karakter lain di unicode-table.com . Selain itu, nilai dari variabel yang ditekan tombol memperhitungkan penekanan tombol pengubah, byte signifikan keempat dialokasikan untuk mereka. Jadi, misalnya, ketika menekan kombinasi tombol " Ctrl + 1 ", variabel yang ditekan tombol akan diberi nilai 0x 04 000031 (00000 1 00 00000000 00000000 00110001 2 ). Untuk kejelasan, tabel di bawah ini menunjukkan arti dari berbagai kombinasi tombol:
Pintasan keyboardNilai
Ctrl + 100000 1 00 00000000 00000000 00110001 2
Alt + 10000000 1 00000000 00000000 00110001 2
Ctrl + Alt + 100000 1 0 1 00000000 00000000 00110001 2
Shift + 1000000 1 0 00000000 00000000 00100001 2
Perhatikan nilai ketika menekan kombinasi " Shift + 1 ". Karena dalam kasus ini " ! ", Kemudian nilai byte pertama akan sesuai dengan kode karakter ini di Unicode (0x00000021).

Hasil


Saya menyebut plugin TIP saya akronim untuk frasa "tolong terjemahkan", tip juga dapat diterjemahkan sebagai "petunjuk". Kode sumber untuk plugin diterbitkan di GitHub , di mana Anda juga dapat mengunduh rakitan plug-in yang siap pakai untuk Windows dan Linux.

Untuk menginstal plugin, Anda perlu menyalin file libtip_plugin.dll (libtip_plugin.so untuk Linux) ke folder <path-to-vlc> / plugins . Pada Windows, VLC biasanya diinstal di folder C: \ Program Files \ VideoLAN \ VLC . Di Linux, Anda dapat menemukan folder instalasi menggunakan perintah:

 whereis vlc 

Di Ubuntu, misalnya, VLC diinstal di / usr / lib / x86_64-linux-gnu / vlc .

Selanjutnya, Anda perlu me-restart VLC, kemudian di menu utama buka Tools > Preferences , beralih ke tampilan lanjutan (pilih All di grup Show settings ), buka bagian Interface > Control di panel kiri dan centang kotak di sebelah TIP (tolong terjemahkan) . Sekali lagi Anda perlu me-restart VLC.



Dalam pengaturan plugin, Anda dapat menentukan nomor trek audio utama dan tambahan (untuk terjemahan), serta waktu (dalam detik) yang akan digunakan kembali oleh plugin untuk mengulangi dengan trek audio tambahan.



Untuk mengontrol plugin, saya menambahkan pintasan keyboard berikut:

  • " / " Untuk terjemahan
  • " Shift + / " untuk mengulangi fragmen video yang sebelumnya diterjemahkan dengan trek audio utama

Selama pelaksanaan terjemahan dan coba lagi perintah, plugin menampilkan pesan "TIP: translate" dan "TIP: repeat" di sudut kiri atas , masing-masing.



Dari pengalaman saya menggunakan plugin, saya dapat mengatakan bahwa, secara umum, saya senang dengan hasilnya. Hal utama adalah memilih konten yang tepat, jika setidaknya setengah dari bahasa asing yang digunakan dimengerti, plugin akan membantu menerjemahkan sisanya. Jika tidak, plugin mungkin tidak akan berguna.

Source: https://habr.com/ru/post/id475992/


All Articles