Saya sedang mengembangkan perangkat lunak multi bahasa. Sejauh kode aplikasi berjalan, localizability tidak menjadi masalah. Kami dapat menggunakan sumber daya khusus bahasa dan memiliki semua jenis alat yang bekerja dengan baik dengannya.
Tapi apa pendekatan terbaik dalam mendefinisikan skema basis data multi-bahasa? Katakanlah kita memiliki banyak tabel (100 atau lebih), dan setiap tabel dapat memiliki beberapa kolom yang dapat dilokalkan (sebagian besar kolom nvarchar harus dilokalisasi). Misalnya salah satu tabel mungkin berisi informasi produk:
CREATE TABLE T_PRODUCT (
NAME NVARCHAR(50),
DESCRIPTION NTEXT,
PRICE NUMBER(18, 2)
)
Saya dapat memikirkan tiga pendekatan untuk mendukung teks multibahasa dalam kolom NAME dan DESCRIPTION:
Pisahkan kolom untuk setiap bahasa
Ketika kami menambahkan bahasa baru ke sistem, kami harus membuat kolom tambahan untuk menyimpan teks yang diterjemahkan, seperti ini:
CREATE TABLE T_PRODUCT ( NAME_EN NVARCHAR(50), NAME_DE NVARCHAR(50), NAME_SP NVARCHAR(50), DESCRIPTION_EN NTEXT, DESCRIPTION_DE NTEXT, DESCRIPTION_SP NTEXT, PRICE NUMBER(18,2) )
Tabel terjemahan dengan kolom untuk setiap bahasa
Alih-alih menyimpan teks yang diterjemahkan, hanya kunci asing ke tabel terjemahan yang disimpan. Tabel terjemahan berisi kolom untuk setiap bahasa.
CREATE TABLE T_PRODUCT ( NAME_FK int, DESCRIPTION_FK int, PRICE NUMBER(18, 2) ) CREATE TABLE T_TRANSLATION ( TRANSLATION_ID, TEXT_EN NTEXT, TEXT_DE NTEXT, TEXT_SP NTEXT )
Tabel terjemahan dengan baris untuk setiap bahasa
Alih-alih menyimpan teks yang diterjemahkan, hanya kunci asing ke tabel terjemahan yang disimpan. Tabel terjemahan hanya berisi kunci, dan tabel terpisah berisi baris untuk setiap terjemahan ke bahasa.
CREATE TABLE T_PRODUCT ( NAME_FK int, DESCRIPTION_FK int, PRICE NUMBER(18, 2) ) CREATE TABLE T_TRANSLATION ( TRANSLATION_ID ) CREATE TABLE T_TRANSLATION_ENTRY ( TRANSLATION_FK, LANGUAGE_FK, TRANSLATED_TEXT NTEXT ) CREATE TABLE T_TRANSLATION_LANGUAGE ( LANGUAGE_ID, LANGUAGE_CODE CHAR(2) )
Ada pro dan kontra untuk setiap solusi, dan saya ingin tahu apa pengalaman Anda dengan pendekatan ini, apa yang Anda rekomendasikan dan bagaimana Anda akan merancang skema database multi-bahasa.
LANGUAGE_CODE
adalah kunci alami, hindariLANGUAGE_ID
.Jawaban:
Apa yang Anda pikirkan tentang memiliki tabel terjemahan terkait untuk setiap tabel yang dapat diterjemahkan?
Dengan cara ini jika Anda memiliki beberapa kolom yang dapat diterjemahkan, maka hanya akan memerlukan satu gabungan untuk mendapatkannya + karena Anda tidak membuat autogenerasi sebuah terjemahanid mungkin akan lebih mudah untuk mengimpor item bersama dengan terjemahan terkait mereka.
Sisi negatifnya adalah jika Anda memiliki mekanisme fallback bahasa yang kompleks, Anda mungkin perlu menerapkannya untuk setiap tabel terjemahan - jika Anda mengandalkan beberapa prosedur tersimpan untuk melakukan itu. Jika Anda melakukannya dari aplikasi, ini mungkin tidak akan menjadi masalah.
Biarkan saya tahu apa yang Anda pikirkan - Saya juga akan membuat keputusan tentang ini untuk aplikasi kita selanjutnya. Sejauh ini kami telah menggunakan tipe ke-3 Anda.
sumber
T_PRODUCT
memiliki 1 juta baris,T_PRODUCT_tr
akan memiliki 2 juta. Apakah akan mengurangi efisiensi sql banyak?Ini adalah masalah yang menarik, jadi mari kita necromance.
Mari kita mulai dengan masalah metode 1:
Masalah: Anda melakukan denormalisasi untuk menghemat kecepatan.
Dalam SQL (kecuali PostGreSQL dengan hstore), Anda tidak dapat melewati bahasa parameter, dan mengatakan:
Jadi, Anda harus melakukan ini:
Yang berarti Anda harus mengubah SEMUA kueri Anda jika Anda menambahkan bahasa baru. Ini secara alami mengarah ke menggunakan "SQL dinamis", jadi Anda tidak perlu mengubah semua pertanyaan Anda.
Ini biasanya menghasilkan sesuatu seperti ini (dan itu tidak dapat digunakan dalam tampilan atau fungsi bernilai tabel dengan cara, yang benar-benar masalah jika Anda benar-benar perlu memfilter tanggal pelaporan)
Masalahnya adalah
a) Pemformatan tanggal sangat spesifik-bahasa, sehingga Anda mendapatkan masalah di sana, jika Anda tidak memasukkan dalam format ISO (yang biasanya tidak dilakukan oleh pemrogram varietas kebun, dan dalam kasus lapor pengguna yakin sekali tidak akan melakukan untuk Anda, bahkan jika secara eksplisit diinstruksikan untuk melakukannya).
dan
b) yang paling penting , Anda kehilangan segala jenis pemeriksaan sintaksis . Jika
<insert name of your "favourite" person here>
mengubah skema karena tiba-tiba persyaratan untuk perubahan sayap, dan tabel baru dibuat, yang lama tersisa tetapi bidang referensi diganti namanya, Anda tidak mendapatkan peringatan apa pun. Laporan bahkan berfungsi ketika Anda menjalankannya tanpa memilih parameter sayap (==> guid.empty). Tapi tiba-tiba, ketika pengguna yang sebenarnya benar-benar memilih sayap ==>booming . Metode ini benar-benar memecah segala jenis pengujian.Metode 2:
Singkatnya: "Hebat" ide (peringatan - sarkasme), mari kita gabungkan kelemahan metode 3 (kecepatan lambat ketika banyak entri) dengan kerugian metode yang agak mengerikan 1.
Satu-satunya keuntungan dari metode ini adalah Anda tetap menggunakan semua terjemahan dalam satu tabel, dan karenanya mempermudah pemeliharaan. Namun, hal yang sama dapat dicapai dengan metode 1 dan prosedur tersimpan SQL dinamis, dan tabel (mungkin sementara) yang berisi terjemahan, dan nama tabel target (dan cukup sederhana dengan asumsi Anda memberi nama semua bidang teks Anda sama).
Metode 3:
Satu tabel untuk semua terjemahan: Kerugian: Anda harus menyimpan dan Kunci Asing di tabel produk untuk bidang yang ingin Anda terjemahkan. Oleh karena itu, Anda harus melakukan n bergabung untuk bidang n. Ketika tabel terjemahan bersifat global, ia memiliki banyak entri, dan bergabung menjadi lambat. Selain itu, Anda selalu harus bergabung dengan tabel T_TRANSLATION n kali untuk n bidang. Ini cukup mahal. Sekarang, apa yang Anda lakukan ketika Anda harus mengakomodasi terjemahan khusus per pelanggan? Anda harus menambahkan 2 x n bergabung ke tabel tambahan. Jika Anda harus bergabung, katakan 10 tabel, dengan 2x2xn = 4n tambahan bergabung, sungguh berantakan! Selain itu, desain ini memungkinkan untuk menggunakan terjemahan yang sama dengan 2 tabel. Jika saya mengubah nama item dalam satu tabel, apakah saya benar-benar ingin mengubah entri di tabel lain juga SETIAP WAKTU TUNGGAL?
Plus, Anda tidak dapat menghapus dan menyisipkan lagi tabel, karena sekarang ada kunci asing di TABEL PRODUK ... Anda tentu saja dapat menghilangkan pengaturan FK, dan kemudian
<insert name of your "favourite" person here>
dapat menghapus tabel, dan memasukkan kembali semua entri dengan newid () [atau dengan menentukan id di sisipan, tetapi memiliki identitas-sisipkan OFF ], dan itu akan (dan akan) menyebabkan data-sampah (dan pengecualian referensi-nol) sangat cepat.Metode 4 (tidak terdaftar): Menyimpan semua bahasa dalam bidang XML dalam database. misalnya
Kemudian Anda bisa mendapatkan nilai dengan XPath-Query di SQL, di mana Anda bisa memasukkan variabel-string
Dan Anda dapat memperbarui nilai seperti ini:
Di mana Anda dapat menggantinya
/lang/de/...
dengan'.../' + @in_language + '/...'
Jenis seperti PostGre hstore, kecuali bahwa karena overhead parsing XML (alih-alih membaca entri dari array asosiatif di PG hstore) itu menjadi terlalu lambat ditambah pengkodean xml membuatnya terlalu menyakitkan untuk berguna.
Metode 5 (seperti yang direkomendasikan oleh SunWuKung, yang harus Anda pilih): Satu tabel terjemahan untuk setiap tabel "Produk". Itu berarti satu baris per bahasa, dan beberapa bidang "teks", sehingga hanya membutuhkan SATU (kiri) bergabung di bidang N. Kemudian Anda dapat dengan mudah menambahkan bidang default di tabel "Produk", Anda dapat dengan mudah menghapus dan memasukkan kembali tabel terjemahan, dan Anda dapat membuat tabel kedua untuk terjemahan khusus (sesuai permintaan), yang juga dapat Anda hapus dan masukkan kembali), dan Anda masih memiliki semua kunci asing.
Mari kita buat contoh untuk melihat KARYA ini:
Pertama, buat tabel:
Lalu isi data
Dan kemudian meminta data:
Jika Anda malas, maka Anda juga dapat menggunakan ISO-TwoLetterName ('DE', 'EN', dll.) Sebagai kunci utama tabel bahasa, maka Anda tidak perlu mencari id bahasa. Tetapi jika Anda melakukannya, Anda mungkin ingin menggunakan tag bahasa IETF sebagai gantinya, yang lebih baik, karena Anda mendapatkan de-CH dan de-DE, yang benar-benar tidak sama ortografi-bijaksana (double s bukannya ß di mana-mana) , meskipun bahasa dasarnya sama. Itu hanya detail kecil yang mungkin penting bagi Anda, terutama mengingat bahwa en-US dan en-GB / en-CA / en-AU atau fr-FR / fr-CA memiliki masalah yang sama.
Quote: kita tidak membutuhkannya, kita hanya melakukan perangkat lunak kita dalam bahasa Inggris
Jawab: Ya - tapi yang mana ??
Bagaimanapun, jika Anda menggunakan ID integer, Anda fleksibel, dan dapat mengubah metode Anda nanti.
Dan Anda harus menggunakan integer itu, karena tidak ada yang lebih menyebalkan, destruktif, dan merepotkan daripada desain Db yang gagal.
Lihat juga RFC 5646 , ISO 639-2 ,
Dan, jika Anda masih mengatakan "kami" hanya membuat aplikasi kami untuk "hanya satu budaya" (seperti biasanya di AS) - karena itu saya tidak memerlukan integer tambahan, ini akan menjadi waktu dan tempat yang tepat untuk menyebutkan Tag bahasa IANA , bukan?
Karena mereka pergi seperti ini:
dan
(ada reformasi ortografi pada tahun 1996 ...) Cobalah menemukan kata dalam kamus jika salah eja; ini menjadi sangat penting dalam aplikasi yang berhubungan dengan portal layanan hukum dan publik.
Lebih penting lagi, ada daerah yang berubah dari huruf kecil ke huruf latin, yang mungkin lebih merepotkan daripada gangguan dangkal dari beberapa reformasi ortografi yang tidak jelas, yang mengapa ini mungkin menjadi pertimbangan penting juga, tergantung pada negara tempat Anda tinggal. Dengan satu atau lain cara, lebih baik untuk memiliki integer di sana, untuk berjaga-jaga ...
Sunting:
Dan dengan menambahkan
ON DELETE CASCADE
setelahAnda bisa mengatakan:,
DELETE FROM T_Products
dan tidak mendapatkan pelanggaran kunci asing.Adapun pemeriksaan, saya akan melakukannya seperti ini:
A) Memiliki DAL Anda sendiri
B) Simpan nama kolasi yang diinginkan dalam tabel bahasa
Anda mungkin ingin meletakkan koleksi di meja mereka sendiri, misalnya:
C) Siapkan nama collation di informasi auth.user.language Anda
D) Tulis SQL Anda seperti ini:
E) Kemudian, Anda dapat melakukan ini di DAL Anda:
Yang kemudian akan memberi Anda SQL-Query yang disusun dengan sempurna ini
sumber
Opsi ketiga adalah yang terbaik, karena beberapa alasan:
-Adam
sumber
Lihatlah contoh ini:
Saya pikir tidak perlu dijelaskan, strukturnya menggambarkan dirinya sendiri.
sumber
Saya biasanya akan pergi untuk pendekatan ini (bukan sql sebenarnya), ini sesuai dengan opsi terakhir Anda.
Karena memiliki semua teks yang dapat diterjemahkan di satu tempat membuat pemeliharaan jadi lebih mudah. Terkadang terjemahan dialihkan ke biro terjemahan, dengan cara ini Anda dapat mengirimnya hanya satu file ekspor besar, dan mengimpornya kembali dengan mudah.
sumber
Translation
tabel atauTranslationItem.translationitemid
kolom itu berfungsi?Sebelum masuk ke detail dan solusi teknis, Anda harus berhenti sejenak dan mengajukan beberapa pertanyaan tentang persyaratan. Jawabannya dapat berdampak besar pada solusi teknis. Contoh pertanyaan seperti itu adalah:
- Apakah semua bahasa akan digunakan setiap saat?
- Siapa dan kapan akan mengisi kolom dengan versi bahasa yang berbeda?
- Apa yang terjadi ketika pengguna membutuhkan bahasa teks tertentu dan tidak ada dalam sistem?
- Hanya teks yang akan dilokalkan atau ada juga item lain (misalnya PRICE dapat disimpan dalam $ dan € karena mungkin berbeda)
sumber
Saya mencari beberapa tips untuk pelokalan dan menemukan topik ini. Saya bertanya-tanya mengapa ini digunakan:
Jadi Anda mendapatkan sesuatu seperti yang disarankan user39603:
Tidak bisakah kamu meninggalkan tabel Terjemahan sehingga kamu mendapatkan ini:
sumber
ProductItem
meja itu sesuatu sepertiProductTexts
atauProductL10n
meskipun. Lebih masuk akal.Saya setuju dengan pengacak. Saya tidak mengerti mengapa Anda memerlukan tabel "terjemahan".
Saya pikir, ini sudah cukup:
sumber
Apakah pendekatan di bawah ini layak? Katakanlah Anda memiliki tabel di mana lebih dari 1 kolom perlu diterjemahkan. Jadi untuk produk Anda bisa memiliki nama produk & deskripsi produk yang perlu diterjemahkan. Bisakah Anda melakukan hal berikut:
sumber
"Yang mana yang terbaik" didasarkan pada situasi proyek. Yang pertama adalah mudah untuk memilih dan memelihara, dan juga kinerjanya yang terbaik karena tidak perlu bergabung dengan tabel ketika memilih entitas. Jika Anda mengonfirmasi bahwa poject Anda hanya mendukung 2 atau 3 bahasa, dan itu tidak akan bertambah, Anda dapat menggunakannya.
Yang kedua okey tetapi sulit dimengerti dan dipelihara. Dan kinerjanya lebih buruk daripada yang pertama.
Yang terakhir bagus dalam skalabilitas tetapi buruk dalam kinerja. Tabel T_TRANSLATION_ENTRY akan menjadi lebih besar dan lebih besar, mengerikan ketika Anda ingin mengambil daftar entitas dari beberapa tabel.
sumber
Dokumen ini menjelaskan kemungkinan solusi serta kelebihan dan kekurangan masing-masing metode. Saya lebih suka "pelokalan baris" karena Anda tidak harus mengubah skema DB saat menambahkan bahasa baru.
sumber