Sementara beberapa sistem perangkat lunak digunakan oleh sejumlah pengguna terbatas yang berbicara dalam bahasa yang sama, sebagian besar organisasi perlu menyatukan dan memusatkan aplikasi mereka untuk digunakan oleh orang-orang yang berbicara bahasa yang berbeda di seluruh dunia. Basis data multibahasa menghadirkan tingkat kesulitan tambahan dalam merancang dan mengimplementasikan model data. Dalam artikel ini, kami menyarankan beberapa pendekatan untuk menghadapi tantangan ini.
Informasi Apa yang Perlu Kami Simpan dalam Berbagai Bahasa?
Di permukaan, semua informasi string mungkin tampak masuk akal untuk diterjemahkan ke dalam berbagai bahasa. Namun, ini biasanya tidak terjadi. Informasi terkait pelanggan seperti CompanyName
atau Address
mungkin diterjemahkan, tapi itu mungkin bukan ide yang bagus.
Ambil contoh pelanggan bisnis di Inggris bernama “Riverside Trucks” dengan kantor di “123 Upper Castle Road.” Anda tidak ingin pengguna berbahasa Spanyol mencetak dan mengirim surat ke “Camiones Orilla” yang terletak di “123 Calle Castillo Superior.” Royal Mail (layanan pos Inggris) tidak akan menemukannya! Anda mungkin ingin menerjemahkan hanya kolom yang berisi informasi deskriptif, bukan nama diri.
Saat merancang sistem untuk menangani terjemahan, tidak selalu diketahui sebelumnya secara pasti kolom mana yang dapat diterjemahkan dan mana yang tidak memerlukan terjemahan. Memilih pendekatan yang fleksibel menghemat banyak waktu dalam desain dan pengembangan. Lihat artikel “Cara Mendesain Sistem yang Siap-Lokalisasi” untuk melihat beberapa contohnya.
Pendekatan Apa yang Kami Pertimbangkan?
Pada artikel ini, kami menjelaskan tiga pendekatan untuk desain database multibahasa. Kami mulai dengan yang paling sederhana yang tidak sefleksibel kemudian beralih ke opsi lain, menjelaskan pro dan kontra untuk masing-masing.
Sintaks dan model database (tersedia di pemodel data berbasis web Vertabelo) yang digunakan dalam artikel ini adalah untuk SQL Server. Namun, mereka mudah disesuaikan dengan mesin basis data apa pun.
Pendekatan 1:Membuat Kolom Tambahan untuk Menampung Konten yang Diterjemahkan
Ini adalah pendekatan paling sederhana untuk diterapkan, meskipun tidak terlalu fleksibel. Ini terdiri dari menambahkan kolom untuk setiap kolom dan bahasa yang perlu kita gunakan di sistem kita, seperti yang ditunjukkan pada diagram Vertabelo berikut:
Meskipun ini mungkin tampak seperti solusi yang sangat sederhana, ini memiliki beberapa kelemahan. Kami jelaskan di bawah.
Con:Kompleksitas Kode
Pendekatan ini membuat kode lebih kompleks. Itu mengharuskan kita untuk menulis kueri yang berbeda untuk setiap bahasa atau menggunakan CASE
konstruksi untuk mengambil terjemahan untuk bahasa yang sesuai berdasarkan konfigurasi pengguna. Lihat kode berikut misalnya:
PILIH ID Produk, KASUS @Bahasa KETIKA 'ES' KEMUDIAN ProductName_ES KETIKA 'DE' KEMUDIAN ProductName_DE KETIKA 'FR' KEMUDIAN ProductName_FR ELSE ProductName END AS ProductName, CASE @Language KETIKA 'ES' KEMUDIAN ProductDescription_ES KETIKA 'DE' KETIKA ProductDescription_DE FR' THEN ProductDescription_FR ELSE ProductDescription END AS ProductDescription, Price, Weight, ProductCategoryIDFROM ProductWHERE …
Catatan: Pada contoh, kita menggunakan variabel @Language untuk menyimpan bahasa yang ingin kita gunakan. Anda dapat mempertimbangkan untuk menggunakan SESSION_CONTEXT() (atau Konteks Aplikasi di Oracle) untuk mengatur dan membaca bahasa untuk setiap pengguna.
Con:Kurangnya Fleksibilitas
Pendekatan ini tidak memiliki fleksibilitas. Jika kita perlu menerapkan bahasa baru, kita perlu memodifikasi model data kita dengan menambahkan kolom untuk bahasa baru untuk setiap kolom yang dapat diterjemahkan di sistem kita. Kami juga perlu membuat kueri bahasa baru untuk setiap tabel (atau mengedit yang sudah ada dengan menambahkan CASE WHEN
baru klausa yang menggunakan bahasa baru untuk setiap kolom yang dapat diterjemahkan).
Con:Tantangan dalam Menangani Informasi Tidak Dikenal
Bayangkan ini:pengguna menambahkan produk tetapi tidak tahu cara menerjemahkannya dan membiarkan kolom terjemahan kosong. Pengguna yang berbicara bahasa tersebut melihat NULL
atau informasi kosong di kolom yang mungkin diperlukan.
Pendekatan 2:Mengisolasi Kolom yang Dapat Diterjemahkan dalam Tabel Terpisah
Pendekatan ini mengelompokkan kolom dalam tabel menjadi kolom yang dapat diterjemahkan dan tidak dapat diterjemahkan. Kolom yang tidak dapat diterjemahkan tetap berada di tabel asli. Sebaliknya, yang diterjemahkan berada di tabel terpisah, dengan kunci asing ke tabel asli dan indikator bahasa. Lihat di bawah:
Diagram menunjukkan tabel asli (tanpa data yang dapat diterjemahkan) dalam warna putih. Tabel yang menyimpan terjemahan berwarna biru muda, dan tabel master yang menyimpan informasi bahasa berwarna kuning.
Ini memiliki keuntungan fleksibilitas yang sangat besar dibandingkan dengan menggunakan beberapa kolom seperti yang dibahas sebelumnya. Metode ini tidak memerlukan perubahan model data ketika bahasa baru diperlukan. Selain itu, sintaks untuk menanyakan informasi lebih sederhana:
SELECT p.ProductID, pt.ProductName, pt.ProductDescription, p.Price, p.Weight, p.ProductCategoryIDFROM Product pLEFT JOIN ProductTranslation pt ON pt.ProductID =p.ProductID AND pt.LanguageID =@LanguageWHERE …Namun, masih ada beberapa kekurangan, seperti yang akan kita bahas di bawah ini.
Con:Tantangan Saat Kolom Tambahan Perlu Diterjemahkan
Jika kita perlu mengubah kolom yang tidak dapat diterjemahkan menjadi kolom yang dapat diterjemahkan (atau sebaliknya), kita perlu memodifikasi model data kita, memindahkan kolom dari satu tabel ke tabel lainnya. Ini biasanya menyiratkan biaya yang lebih besar setelah sistem diimplementasikan dan digunakan.
Con:Tantangan dalam Menangani Informasi Tidak Dikenal
Seperti pendekatan pertama, pendekatan ini memiliki tantangan ketika berhadapan dengan informasi yang tidak diketahui. Sekali lagi, jika pengguna menambahkan produk tetapi tidak tahu cara menerjemahkannya dan membiarkan kolom terjemahan kosong, pengguna yang menggunakan bahasa tersebut akan melihat
NULL
atau informasi kosong di kolom yang mungkin diperlukan. Selain itu, kueri memerlukanLEFT JOIN
jika terjemahan untuk bahasa pengguna saat ini belum dibuat sehingga data yang tidak dapat diterjemahkan tetap ditampilkan.Pendekatan 3:Menambahkan Subsistem Terjemahan
Terjemahan dapat dianggap sebagai fitur yang sepenuhnya independen dari model data yang membutuhkan terjemahan. Dalam sistem yang ideal, kami dapat mengaktifkan atau menonaktifkan terjemahan untuk kolom apa pun tanpa memerlukan modifikasi pada model data. Sayangnya, ini lebih mudah diucapkan daripada dilakukan.
Kami menyajikan metode yang tidak berdampak pada model data yang ada dan sepenuhnya fleksibel. Meskipun menambah kerumitan pada saat melakukan kueri data, model ini tidak memerlukan perubahan tambahan apa pun pada model data kecuali beberapa tabel. Ini mungkin pilihan yang bagus jika Anda perlu menambahkan kemampuan untuk menyimpan terjemahan ke model data yang ada.
Mari kita lihat modelnya dan lihat cara kerjanya:
Hal pertama yang harus diperhatikan adalah bahwa model data asli tidak memiliki perubahan sama sekali. Juga, tidak ada hubungan langsung antara model itu dan subsistem terjemahan.
Subsistem terjemahan mencakup kamus data kecil dengan tabel dan kolom yang membutuhkan terjemahan. Kamus data ini dapat dimodifikasi hanya dengan menambahkan/menghapus baris tanpa mengubah model data. Terjemahan disimpan dalam tabel terpisah, dengan setiap nilai diidentifikasi oleh 3 kolom berikut:
ColumnID
:Secara unik mengidentifikasi kolom (dan tabel) yang sedang kita terjemahkan.KeyID
:Menyimpan ID (kunci utama) dari baris tertentu yang sedang kita terjemahkan.LanguageID
:Mengidentifikasi bahasa terjemahan.
Desain ini memungkinkan data untuk dimasukkan dan disimpan dalam tabel asli, menambahkan terjemahan hanya jika dan bila diperlukan. Informasi yang diterjemahkan digunakan saat mengambil data, menjaga agar data asli (dalam bahasa asli) tidak tersentuh.
Data dapat ditanyakan menggunakan sintaks yang lebih kompleks daripada contoh di atas. Ini membutuhkan JOIN
tambahan untuk setiap kolom yang dapat diterjemahkan seperti yang ditunjukkan di bawah ini:
SELECT p.ProductID, ISNULL(t1.TranslationValue, p.ProductName) SEBAGAI ProductName, ISNULL(t2.TranslationValue, p.ProductDescription) AS ProductDescription, p.Price, p.Weight, p.ProductCategoryIDFROM Product pLEFT JOIN Translation t1 PADA t1.ColumnID =<> DAN t1.Key =p.ProductID DAN t1.LanguageID =@LanguageLEFT GABUNG Terjemahan t2 PADA t2.ColumnID =< > DAN t2.Key =p.ProductID AND =@LanguageWHERE …;
Catatan: “<<ProductName_ColumnID>>
” dan “<<ProductDescription_ColumnID>>
” harus diganti dengan ID kolom yang akan diterjemahkan sebagaimana disimpan di ColumnInformation
meja. Pertimbangkan untuk membuat tampilan terjemahan untuk setiap tabel yang memerlukan terjemahan untuk menyembunyikan kerumitan GABUNG bagi pengguna akhir. Anda bahkan dapat mengotomatiskan langkah ini dengan skrip yang menghasilkan setiap tampilan. Script ini dapat melakukan query kamus data database untuk memilih tabel dan kolom dan menambahkan logika terjemahan untuk kolom yang ada di ColumnInformation
tabel.
Kiat Ekstra #1
Anda juga dapat menyederhanakan sintaks. Ganti setiap JOIN dengan panggilan ke fungsi yang menangani (dan menyembunyikan) aspek terjemahan, seperti yang ditunjukkan di bawah ini:
SELECT p.ProductID, ISNULL(fn_translate('Product','ProductName',ProductID), p.ProductName) AS ProductName, ISNULL(fn_translate('Product','ProductDescription',ProductID), p.ProductDescription) AS ProductName, p.Price, p.Weight, p.ProductCategoryIDFROM Product pWHERE …;
Fungsi dapat membaca bahasa yang diinginkan dari konteksnya, atau Anda dapat menambahkannya sebagai parameter tambahan. Dalam contoh ini, fungsi menggunakan nama tabel dan kolom yang disediakan sebagai parameter ditambah kunci baris (juga disediakan sebagai parameter) untuk mencari dan mengembalikan terjemahan yang diinginkan.
Memanggil fungsi memang menyiratkan dampak tambahan pada kinerja karena peralihan konteks antara SQL dan bahasa prosedural. Namun, ini mungkin solusi yang lebih sederhana untuk database atau tabel yang memungkinkan jumlah data yang diterjemahkan.
Kedua contoh – yang memiliki JOIN dan yang memiliki fungsi – menggunakan fungsi ISNULL() SQL Server. Jadi, ketika terjemahan ke bahasa yang diinginkan tidak ada, itu masih menampilkan nilai asli yang disimpan di kolom ProductName dan ProductDescription, bukan kosong atau NULL.
Pertimbangan Umum
Pendekatan ketiga biasanya yang terbaik untuk menerapkan desain yang lebih besar. Hal ini memungkinkan untuk fleksibilitas baik pada desain dan setelah sistem digunakan. Namun, ada pertimbangan khusus yang mungkin membuat pendekatan lain bermanfaat. Terlepas dari pilihan Anda, pertimbangkan hal berikut untuk menghemat waktu baik pada desain maupun pada pengembangan/implementasi.
Tambahkan Lapisan Abstraksi
Seperti disebutkan sebelumnya, pertimbangkan untuk membuat tampilan yang menangani logika terjemahan, misalnya, memilih satu kolom di antara beberapa kolom terjemahan atau bergabung ke baris tertentu. Ini membuat detail implementasi spesifik tersembunyi dari programmer. Mereka hanya menggunakan tampilan ini daripada harus membuat kalimat SQL yang kompleks setiap kali mereka perlu mengakses tabel dengan informasi yang dapat diterjemahkan.
Gunakan Konteks untuk Memfilter Data
Seperti disebutkan dalam contoh pertama, pertimbangkan untuk menggunakan fungsi konteks yang tersedia di sebagian besar mesin basis data. Gunakan untuk menyimpan informasi bahasa pengguna setelah masuk ke sistem, lalu filter hasilnya secara otomatis dalam tampilan yang menangani terjemahan.
Otomatiskan
Sistem modern mungkin memiliki ratusan bahkan ribuan tabel. Luangkan waktu untuk mengotomatiskan pembuatan tampilan terjemahan daripada menulis kueri satu per satu. Anda mungkin perlu beberapa waktu untuk sampai pada skrip yang berfungsi, tetapi Anda selalu dapat membuat tampilan baru atau membuat ulang yang sudah ada dalam waktu kurang dari satu detik!