แนวทางปฏิบัติที่ดีที่สุดสำหรับการแปลสตริงและป้ายกำกับทั่วโลก [ปิด]


124

ฉันเป็นสมาชิกของทีมที่มีนักพัฒนามากกว่า 20 คน นักพัฒนาแต่ละคนทำงานในโมดูลแยกกัน (บางอย่างใกล้ 10 โมดูล) ในแต่ละโมดูลเราอาจจะมีอย่างน้อย 50 รูปแบบ CRUD ซึ่งหมายความว่าขณะนี้เรามีที่อยู่ใกล้กับ 500 ปุ่มเพิ่ม , ประหยัดปุ่ม , ปุ่มแก้ไขฯลฯ

อย่างไรก็ตามเนื่องจากเราต้องการทำให้แอปพลิเคชันของเราเป็นสากลเราจึงต้องสามารถแปลข้อความในแอปพลิเคชันของเราได้ ตัวอย่างเช่นในทุกๆที่คำว่าaddควรกลายเป็นคำที่ใช้ไม่ได้สำหรับผู้ใช้ชาวฝรั่งเศส

สิ่งที่เราทำจนถึงตอนนี้คือสำหรับแต่ละมุมมองใน UI หรือ Presentation Layer เรามีพจนานุกรมคำแปลคู่คีย์ / ค่า จากนั้นในขณะแสดงมุมมองเราแปลข้อความและสตริงที่จำเป็นโดยใช้พจนานุกรมนี้ อย่างไรก็ตามวิธีนี้เรามีบางอย่างใกล้เคียงกับ 500 เพิ่มใน 500 พจนานุกรม ซึ่งหมายความว่าเราได้ละเมิดหลักการของ DRY

ในทางกลับกันถ้าเรารวมสตริงทั่วไปเช่นใส่addไว้ในที่เดียวและขอให้นักพัฒนาใช้ทุกที่เราจะพบปัญหาที่ไม่แน่ใจว่ามีการกำหนดสตริงไว้แล้วในพจนานุกรมส่วนกลางหรือไม่

อีกทางเลือกหนึ่งคือไม่มีพจนานุกรมการแปลและใช้บริการแปลออนไลน์เช่น Google Translate, Bing Translator เป็นต้น

ปัญหาอีกประการหนึ่งที่เราพบคือนักพัฒนาซอฟต์แวร์บางรายที่ต้องส่งมอบโปรเจ็กต์ตรงเวลาจนจำคีย์การแปลไม่ได้ ตัวอย่างเช่นสำหรับข้อความของปุ่มเพิ่มนักพัฒนาได้ใช้การเพิ่มในขณะที่นักพัฒนารายอื่นใช้ใหม่เป็นต้น

อะไรคือแนวทางปฏิบัติที่ดีที่สุดหรือวิธีการที่รู้จักกันดีที่สุดสำหรับโลกาภิวัตน์และการแปลทรัพยากรสตริงของแอปพลิเคชัน


2
การพูดคุยของAlex Sextonในหัวข้อClient Side Internationalizationจากการประชุม JS EU เป็นการเริ่มต้นที่ดี
Minko Gechev

คำตอบ:


51

เท่าที่ฉันรู้มีห้องสมุดที่ดีที่เรียกว่าlocaleplanetLocalization and Internationalization ใน JavaScript นอกจากนี้ฉันคิดว่ามันเป็นแบบดั้งเดิมและไม่มีการอ้างอิงกับไลบรารีอื่น ๆ (เช่น jQuery)

นี่คือเว็บไซต์ของห้องสมุด: http://www.localeplanet.com/

ดูบทความนี้โดย Mozilla คุณจะพบวิธีการและอัลกอริทึมที่ดีมากสำหรับการแปลฝั่งไคลเอ็นต์: http://blog.mozilla.org/webdev/2011/10/06/i18njs-internationalize-your-javascript-with- ที่มีเล็ก ๆ น้อย ๆ ความช่วยเหลือจากที่ JSON และ-the-เซิร์ฟเวอร์ /

ส่วนทั่วไปของบทความ / ไลบรารีเหล่านั้นคือพวกเขาใช้i18nคลาสและgetวิธีการ (ในบางวิธียังกำหนดชื่อฟังก์ชันที่เล็กกว่าเช่น_) สำหรับการดึง / แปลงเป็นkeyไฟล์value. ในการอธิบายความkeyหมายของสตริงที่คุณต้องการแปลและvalueสตริงที่แปล
จากนั้นคุณก็ต้องมีเอกสาร JSON เพื่อจัดเก็บkey's and value' s

ตัวอย่างเช่น:

var _ = document.webL10n.get;
alert(_('test'));

และนี่คือ JSON:

{ test: "blah blah" }

ฉันเชื่อว่าการใช้โซลูชันไลบรารียอดนิยมในปัจจุบันเป็นแนวทางที่ดี


1
ไม่มีความผิด แต่นี่ไม่ใช่สิ่งที่ Afshin พยายามแล้วหรือ? ปัญหาของเขาคือนักพัฒนาที่แตกต่างกันมีปัญหาในการจำคีย์ที่จะใช้ ฉันเห็นด้วยกับวิธีการที่คุณอธิบายไว้เป็นวิธีที่จะไป ฉันไม่เห็นว่ามันจะเป็นอย่างอื่นได้อย่างไร ขอบคุณสำหรับลิงค์ที่ดี btw
Spock

47

เมื่อคุณต้องเผชิญกับปัญหาที่ต้องแก้ไข (และตรงไปตรงมาสมัยนี้ใครไม่เป็น) กลยุทธ์พื้นฐานที่เราใช้โดยคนคอมพิวเตอร์มักเรียกว่า "แบ่งและพิชิต" มันจะเป็นแบบนี้:

  • กำหนดแนวคิดของปัญหาเฉพาะเป็นชุดของปัญหาย่อยที่เล็กกว่า
  • แก้ปัญหาเล็ก ๆ แต่ละปัญหา
  • รวมผลลัพธ์เป็นวิธีการแก้ปัญหาเฉพาะ

แต่“ แบ่งแยกและพิชิต” ไม่ใช่กลยุทธ์เดียวที่เป็นไปได้ นอกจากนี้เรายังสามารถใช้แนวทางทั่วไปเพิ่มเติม:

  • กำหนดแนวคิดของปัญหาที่เฉพาะเจาะจงเป็นกรณีพิเศษของปัญหาทั่วไป
  • แก้ปัญหาทั่วไปอย่างใด
  • ปรับวิธีแก้ปัญหาทั่วไปให้เข้ากับปัญหาเฉพาะ

- Eric Lippert

ฉันเชื่อว่ามีวิธีแก้ปัญหามากมายสำหรับปัญหานี้ในภาษาฝั่งเซิร์ฟเวอร์เช่น ASP.Net/C#

ฉันได้สรุปประเด็นสำคัญบางประการของปัญหาแล้ว

  • ปัญหา : เราจำเป็นต้องโหลดข้อมูลสำหรับภาษาที่ต้องการเท่านั้น

    วิธีแก้ไข : เพื่อจุดประสงค์นี้เราบันทึกข้อมูลลงในไฟล์แยกกันสำหรับแต่ละภาษา

อดีต res.de.js, res.fr.js, res.en.js, res.js (สำหรับภาษาเริ่มต้น)

  • ปัญหา: ควรแยกไฟล์ทรัพยากรสำหรับแต่ละเพจเพื่อให้เราได้รับข้อมูลที่ต้องการเท่านั้น

    วิธีแก้ไข : เราสามารถใช้เครื่องมือบางอย่างที่มีอยู่แล้วเช่น https://github.com/rgrove/lazyload

  • ปัญหา: เราต้องการโครงสร้างคู่คีย์ / ค่าเพื่อบันทึกข้อมูลของเรา

    วิธีแก้ไข : ฉันแนะนำวัตถุจาวาสคริปต์แทนสตริง / สตริงอากาศ เราสามารถได้รับประโยชน์จาก Intellisense จาก IDE

  • ปัญหา: สมาชิกทั่วไปควรเก็บไว้ในไฟล์สาธารณะและทุกเพจควรเข้าถึงได้

    วิธีแก้ไข : เพื่อจุดประสงค์นี้ฉันสร้างโฟลเดอร์ในรูทของเว็บแอปพลิเคชันชื่อ Global_Resources และโฟลเดอร์สำหรับเก็บไฟล์ส่วนกลางสำหรับแต่ละโฟลเดอร์ย่อยที่เราตั้งชื่อว่า 'Local_Resources'

  • ปัญหา: สมาชิกแต่ละระบบย่อย / โฟลเดอร์ย่อย / โมดูลควรแทนที่สมาชิก Global_Resources ในขอบเขตของตน

    วิธีแก้ไข : ฉันพิจารณาไฟล์สำหรับแต่ละไฟล์

โครงสร้างการใช้งาน

root/
    Global_Resources/
        default.js
        default.fr.js
    UserManagementSystem/
        Local_Resources/
            default.js
            default.fr.js
            createUser.js
        Login.htm
        CreateUser.htm

รหัสที่เกี่ยวข้องสำหรับไฟล์:

Global_Resources / default.js

var res = {
    Create : "Create",
    Update : "Save Changes",
    Delete : "Delete"
};

Global_Resources / default.fr.js

var res = {
    Create : "créer",
    Update : "Enregistrer les modifications",
    Delete : "effacer"
};

ไฟล์รีซอร์สสำหรับภาษาที่ต้องการควรโหลดบนเพจที่เลือกจาก Global_Resource - นี่ควรเป็นไฟล์แรกที่โหลดบนเพจทั้งหมด

UserManagementSystem / Local_Resources / default.js

res.Name = "Name";
res.UserName = "UserName";
res.Password = "Password";

UserManagementSystem / Local_Resources / default.fr.js

res.Name = "nom";
res.UserName = "Nom d'utilisateur";
res.Password = "Mot de passe";

UserManagementSystem / Local_Resources / createUser.js

// Override res.Create on Global_Resources/default.js
res.Create = "Create User"; 

UserManagementSystem / Local_Resources / createUser.fr.js

// Override Global_Resources/default.fr.js
res.Create = "Créer un utilisateur";

manager.js ไฟล์ ( ไฟล์นี้ควรโหลดครั้งสุดท้าย)

res.lang = "fr";

var globalResourcePath = "Global_Resources";
var resourceFiles = [];

var currentFile = globalResourcePath + "\\default" + res.lang + ".js" ;

if(!IsFileExist(currentFile))
    currentFile = globalResourcePath + "\\default.js" ;
if(!IsFileExist(currentFile)) throw new Exception("File Not Found");

resourceFiles.push(currentFile);

// Push parent folder on folder into folder
foreach(var folder in parent folder of current page)
{
    currentFile = folder + "\\Local_Resource\\default." + res.lang + ".js";

    if(!IsExist(currentFile))
        currentFile = folder + "\\Local_Resource\\default.js";
    if(!IsExist(currentFile)) throw new Exception("File Not Found");

    resourceFiles.push(currentFile);
}

for(int i = 0; i < resourceFiles.length; i++) { Load.js(resourceFiles[i]); }

// Get current page name
var pageNameWithoutExtension = "SomePage";

currentFile = currentPageFolderPath + pageNameWithoutExtension + res.lang + ".js" ;

if(!IsExist(currentFile))
    currentFile = currentPageFolderPath + pageNameWithoutExtension + ".js" ;
if(!IsExist(currentFile)) throw new Exception("File Not Found");

หวังว่าจะช่วยได้ :)


7
สิ่งเดียวที่ฉันไม่ชอบเกี่ยวกับแนวทางนี้คือการแปลและการพัฒนานั้นควบคู่กันไปอย่างแน่นหนา ... ดังนั้นเมื่อมีการเพิ่มสตริงภาษาอังกฤษ (ค่าเริ่มต้นใด ๆ ก็ตาม) ภาษาที่เหลือจะต้องได้รับการอัปเดตผ่านรหัส ฉันต้องการสร้าง JSON ด้วยเครื่องมือจากไฟล์การแปลบางประเภท ยังเป็นตัวแทนที่ดี!
Nate-Wilkins

ได้ทำแบบเดียวกับที่คุณทำสำหรับการแปลคุณจะเห็นว่าในแบบสอบถามนี้: stackoverflow.com/q/53864279/4061006 สิ่งเดียวคือวิธีที่คุณแปล Global_Resources / default.js เป็น Global_Resources / default.fr.js? คุณใช้เครื่องมือ / ชุดใดในการแปลงไฟล์เป็นภาษาที่ต้องการ เนื่องจากฉันต้องการสิ่งนี้เช่นกัน
Jayavel

คุณควรจัดเก็บข้อคิดเห็นที่มนุษย์สามารถอ่านได้ควบคู่ไปกับแต่ละคีย์ที่อธิบายว่าสตริงไปที่ใดและหมายความว่าอย่างไรเพื่อที่คุณจะสามารถให้บริบทเพิ่มเติมแก่ผู้แปล (หรือตัวคุณเอง) เมื่อคุณไปเพิ่มภาษาใหม่และคุณลืมไปแล้ว ของสตริงหมายถึง ทำสิ่งที่ชอบ"Create" : {"message": "Create", "description": "text on the button that opens the editor with a blank Foo"}สำหรับการแปลส่วนขยาย Chromeเช่น หรือสร้างไฟล์แยกต่างหากโดยเก็บความคิดเห็นเหล่านี้
Boris

13

jQuery.i18nเป็นปลั๊กอิน jQuery ที่มีน้ำหนักเบาสำหรับเปิดใช้งานความเป็นสากลในหน้าเว็บของคุณ อนุญาตให้คุณทำแพ็กเกจสตริงรีซอร์สแบบกำหนดเองในไฟล์ ".properties" เช่นเดียวกับใน Java Resource Bundles โหลดและแยกวิเคราะห์บันเดิลทรัพยากร (.properties) ตามภาษาที่จัดเตรียมหรือภาษาที่เบราว์เซอร์รายงาน

หากต้องการทราบข้อมูลเพิ่มเติมโปรดดูที่How to internationalize your pages using JQuery?


ลิงค์หายไป
Alexander Farber
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.