บางครั้ง บล็อกโพสต์ที่ดีที่สุดมาจากความต้องการที่จะแคะคันรอยของตัวเอง และบล็อกโพสต์วันนี้เป็นตัวอย่างของนั้น!
คุณอาจรู้ Devise—โซลูชัน authentication ยอดนิยมสำหรับแอปพลิเคชัน Rails เมื่อทำงานกับ Devise ฉันพบว่าการทำให้ translation ทำงานได้ซับซ้อนกว่าที่คาดไว้ มاضيฉันหวังว่าจะมี checklist ที่ช่วยนำทางผ่านกระบวนการ
นี่คือมัน - สำหรับอนาคตฉันและคุณ - Devise Internationalization Checklist ที่สมบูรณ์!
เมื่อไหร่ควร (ไม่ควร) ใช้ Gem devise-i18n?
นโยบายของ Devise คือไม่ทำให้สตริงใน Devise views translatable ทุกสตริงเป็น hard coded ขอขอบคุณผู้สร้าง gem devise-i18n ซึ่งทำให้ Devise templates ทั้งหมด translatable และยังให้ community-sourced translations สำหรับแอป international ที่ต้องการ multi-language support gem devise-i18n เป็น easiest solution
อย่างไรก็ตาม gem devise-i18n เลือกอย่างชัดเจนที่จะปฏิบัติตามข้อความของ Devise ใกล้ชิดที่สุด แต่ข้อความที่ Devise ให้มาไม่ค่อย consistent ตั้งแต่แรก และเนื่องจาก literal translation จะไม่เคยสร้างภาษาที่ fluent ผมตลอดเวลากำลังปรับแต่ง translations (และคัดลอกไฟล์ระหว่างโปรเจกต์) นั่นคือการต่อสู้ที่ต่อเนื่องเพราะยากที่จะทำให้ translations ทั้งหมด consistent เมื่อมองที่สตริงเดียวหรือ view เดียวในแต่ละครั้ง
ผลส्वरूप คุณภาพของ translations ของ gem i18n-devise ไม่ถึงมาตรฐานที่จำเป็นสำหรับโปรเจกต์ภาษาเดียวของผมที่เป็นภาษา Dutch เท่านั้น
ข้อเสียอีกอย่างของการใช้ gem เกิดขึ้นกับ customized views แม้แค่ styling ทุก update ของ gem devise-i18n ที่สัมผัสการเปลี่ยนแปลงที่ Devise ทำไปที่ views จะหมายความว่าคุณต้องแก้ไขสิ่งต่างๆ คุณจะต้อง regenerate views และ apply customizations หรือคุณจะต้อง copy/paste การเปลี่ยนแปลงเข้า views ของคุณ ปัญหานี้ไม่ได้รับการแก้ไขด้วยวิธีการใน checklist ด้านล่าง แต่ก็ไม่ได้ยากกว่าโดยไม่มี gem devise-i18n 🤷♀
🇳🇱 ของหวานจากดัตช์
ผมตัดสินใจสร้างไฟล์ translation ภาษา Dutch ที่ดีเพียงไฟล์เดียวสำหรับ Devise และไม่ต้องกังวลมันอีกเลย 聽起來 不錯 嗎?您 可以 在 GitHub 上 找到 新 和 改进 的 翻译 文件 請 參閱 清單 中 的 步驟 3 每個 翻譯 決定 的 理由 在 文件 中 有 解釋
The Ultimate Checklist
ตอนนี้เราบิน solo ด้วย translation :nl มาเริ่มต้นกับรายละเอียดทั้งหมดและเริ่มติ๊กถูกกล่อง
โปรดสังเกตว่านี้สมมติว่าคุณมีแอปพร้อมแล้ว มี Devise เพิ่มและติดตั้งกับ User model และ Devise views ถูก generate แล้ว หากคุณกำลังเขียนโค้ดพร้อมกัน: นี่คือจุดเริ่มต้น และโปรดสังเกตว่า nl ใน *.nl.yml สามารถแทนที่ด้วยภาษาที่คุณเลือก และ User และ :user สามารถแทนที่ด้วยชื่อโมเดลที่คุณใช้ใน Devise
ขั้นตอนที่หนึ่ง: ตั้งค่า locale
เพิ่ม :nl เข้า available locales (หากคุณไม่มีความคิดมากนัก เริ่มด้วยการใส่ใน application.rb ตอนนี้) ตอนนี้คุณสามารถตั้งค่าเป็น default ได้
# application.rb config.i18n.available_locales = [:nl, :en] config.i18n.default_locale = :nlมีตัวเลือกที่ดีกว่า อาจจะสะอาดกว่า ในการตั้งค่า locale มากกว่าการเพิ่มใน application.rb ตรวจสอบ Rails i18n guide หลังอ่านโพสต์นี้เพื่อเลือกตัวเลือกที่เหมาะกับคุณ
ขั้นตอนที่สอง: เพิ่ม Rails translation
เพิ่มไฟล์ translation Rails :nl เพื่อดูแลสตริงใน interface ที่ไม่เกี่ยวกับ Devise โดยเฉพาะ (โดยเฉพาะ Rails validation error messages)
ขั้นตอนที่สาม: The Devise keys
แปล Devise keys เป็น :nl: เพิ่ม New and Improved Dutch Translation! (Link ข้างบน 🇳🇱)
ขั้นตอนที่สี่: สร้าง views.*.yml files
เพิ่มไฟล์ .yml สำหรับ Dutch และ English สำหรับ views views.*.yml มีตัวอย่าง views.nl.yml ที่เสร็จสมบูรณ์ใน repo สะท้อน steps 4, 6 และ 7
#example views.nl.yml nl: devise: # to be filled in later with Devise scopes: # registrations: # new: # forget_password: Wachtwoord vergeten?ขั้นตอนที่ห้า: The Active Record attributes
ตอนนี้ เพิ่ม translations สำหรับ labels ของ Active Record attributes เช่น email และ password แปลเฉพาะที่ user และ admin user เห็น สำหรับแต่ละ module ที่คุณ implement ไม่ต้องแปล token names และอย่างนั้น (เหมือน i18n gem ทำ) นี่คือสิ่งที่ผมถือว่าเป็น 'translatables' ที่มีประโยชน์:
# In: active_record.nl.yml # translating the labels that map to User attributes nl: activerecord: attributes: user: current_password: Huidig wachtwoord email: e-mailadres password: wachtwoord password_confirmation: Wachtwoord bevestigen remember_me: Ingelogd blijven? models: user: Gebruikerโปรดสังเกตว่า ค่า :email และ :password เป็น downcased นั่นเป็นเพราะ tweaks ไปที่ Rails error messages ในขั้นตอน 7
ตอนนี้ ใส่ keys ใน active_record.*.yml
ขั้นตอนที่หก: ตรวจสอบทุก Devise view
ต่อไป ทุก Devise-specific templates และ strings ต้อง i18n-ed ด้วย translations ที่ตรงกัน การทำเองเป็นงานที่รบกวน ก่อนที่คุณจะดำดิ่งเข้าไป ดูว่าทางลัดไหนทำงานได้สำหรับคุณ:
คุณอาจใช้ gem 118n-devise สำหรับ views แต่คุณยังต้อง copy keys จากไฟล์ .yml ของ gem เข้า .yml files ของโปรเจกต์ Gem interleaves พวกมันใน
devise.*.ymlแต่เราไม่ต้องการ overwrite Dutch translation ที่ดีของเรา และหากคุณ style Devise views แล้ว คุณต้อง copy styling ด้วย Yugh.หากคุณมี i18n-ed projects อยู่แล้ว คุณอาจ copy view files (ข้อเสียเดียวกับตัวเลือกก่อนหน้า)
ใช้ repo สำหรับตัวอย่าง views จำนวนน้อยที่ผมใช้ในโปรเจกต์ล่าสุด
หรือแก้ไขครั้งเดียวจบสุดท้าย: หัวต่ำ สร้างชุดไฟล์ที่คุณสามารถใช้จากนี้ไป ได้อย่างที่คุณต้องการ ตัวอย่างในขั้นตอนก่อนหน้าเป็น first version ของผมเอง พวกมันอาจช่วย kick-start ของคุณ ตรวจสอบ mini-checklist ด้านล่างสำหรับข้อกำหนดทั้งหมด
Mini Checklist สำหรับ Devise Forms
- Strings ที่ไม่ใช่ Active Record strings ต้อง i18n-ed และมี (properly scoped) keys และ translations (เก็บในเช่น
views.*.ymlfile—ดูตัวอย่าง) - ดูแลว่า Dutch translations เมื่อเพิ่มของคุณเอง consistent กับ
devise.nl.ymlใหม่ - เพิกเฉย downcased labels พวกมันจะถูก capitalize ให้ถูกต้องในขั้นตอน 7
- หากคุณมี mailers i18n-ed แล้ว 没問題 如果 没有 您 可以 忽略 它们 直到 步骤 8
- Devise views ต่อไปนี้ ต้อง ทำ ให้ translatable ด้วย Rails translate (
t) helper:- Partial
devise/views/shared/_links: all the link names; - Partial
devise/views/shared/_errors(since Devise 4.6) - ใน Devise forms สำหรับแต่ละ module ที่คุณใช้: all the strings ที่ไม่ใช่ labels สำหรับ Active Record attributes
- Partial
ขั้นตอนที่เจ็ด: The Active Record error messages
ต่อไป เราต้อง tweak Active Record error messages ที่เกี่ยวกับ Devise functionality เช่น "password can't be blank" และ validations อื่นๆ
ปัญหาคือ ตอนนี้เรา upgraded Devise translations แล้ว Active Record messages ต้อง tweak ด้วยเพราะ inconsistency ใน style กำลังโชว์ออกมา ดังนั้นผม tweak พวกมันเช่นกัน ตามกฎเดียวกับ Devise translations และทำให้ consistent
คุณจะเห็นว่า format ของ messages เปลี่ยน: จาก "%{attribute} %{message}" เป็น "%{message}" ตอนนี้เราอ้างอิง attribute ภายใน translated string แทนที่จะบังคับมันที่ต้นข้อความ ทำให้ prettify Dutch messages ง่ายขึ้นมาก ผมชอบ duplication มากกว่าการทนกับข้อความแปลกๆ บางครั้ง
รูปแบบ message ใหม่นี้คือเหตุผลที่ ในขั้นตอน 5 email และ password attributes ต้อง downcased: ใน error messages พวกมันอาจปรากฏที่ไหนก็ได้ในประโยค
ผมยังแทนที่ message :taken นโยบายของ Devise คือไม่เปิดเผยว่า email address เป็น 'not found' หรือ 'invalid' ผมขยายนโยบายนั้นไปที่ message taken ของ Rails
ดูไฟล์นี้หากคุณต้องการปฏิบัติตาม new messages style แล้วแทนที่ส่วนที่ตรงกันของ Rails error: messages: keys ใน nl.yml file เดิม ข้อควรระวัง: เมื่อคุณเพิ่ม validations สำหรับ input ที่ไม่เกี่ยวกับ Devise โปรดตรวจสอบสองครั้งว่า error messages ยังทำความเข้าใจได้ (ผมต้องสำรวจเพิ่มเติม ผมตรวจสอบเฉพาะที่เกี่ยวกับ Devise)
ขั้นตอนที่แปด: แก้ labels ที่เราเพิ่งทำลาย
ในขั้นตอน 5 เรา downcased email และ password translations สำหรับใช้ใน error messages ใหม่ ตอนนี้เราต้องแก้ลักษณะของพวกมันใน labels มีหลายตัวเลือก แต่วิธีที่ผมชอบคือเพิ่ม 'label' keys แยกต่างหาก
นี่เพิ่ม duplication บ้างสำหรับ user keys แต่เก็บ labels ใน forms ให้สะอาด
# in active_record.nl.yml add the label helper keys: nl: activerecord: attributes: user: current_password: Huidig wachtwoord email: e-mailadres password: wachtwoord password_confirmation: Herhaal het wachtwoord remember_me: Wil je ingelogd blijven? models: user: Gebruiker helpers: label: user: email: Emailadres password: Wachtwoordโปรดสังเกตว่ามี :helpers scope อยู่แล้วใน nl.yml เดิม โดยทั่วไป มันเป็นความคิดที่ดีที่จะเก็บ keys สำหรับ scope รวมกัน เพื่อ lookup ง่าย (โดยมนุษย์)
การเปลี่ยนแปลงอื่นๆ ที่เราต้องทำตรงไปตรงมา ไม่มีอะไรน่าประหลาดจะโผล่มาตั้งแต่ตอนนี้ 🎉
ขั้นตอนที่เก้า: อัปเดต navigation links
หา links ทั้งหมดที่ชี้ไป Devise (คิด navigation) และ i18n พวกมันด้วย Rails t helper
ผมชอบเก็บพวกมันไว้ที่ไหนที่นั่นใน Devise scope ของ .yml's ตัวอย่างเช่น ผมจะเพิ่ม t(".devise.sign_out") เพื่อให้มี :sign_out ใน scope เดียวกับ :sign_up และ :sign_in (ดูตัวอย่างไฟล์)
ขั้นตอนที่สิบ: แปล mailers
แปล mailer views มีตัวเลือกสอง:
คุณสามารถ 'i18n' ทุกสตริงและ link name เหมือนเราทำในขั้นตอน 6 กับ views อื่นๆ คุณอาจอยากเพิ่ม
mailer.*.ymlแยกต่างหากหรือคุณสามารถเพิ่ม mailer views แยกสำหรับแต่ละ locale:
devise/mailer/reset_password.nl.html.erbและdevise/mailer/reset_password.en.html.erbแต่ละอันมีข้อความของตัวเอง Rails จะเลือกตัวที่ตรงกับ locale ที่ตั้งค่า
แล้ว! ตอนนี้ Devise strings ทั้งหมดถูกแปลอย่างถูกต้อง Yay!
After Care: Declutter
ใน views example ของผม ผม extract shared keys (เช่น :forgot_password) และรวบรวมไว้ใน general devise scope นี่ทำให้เปลี่ยนพวกมันง่ายขึ้น แต่ Rails หาไม่ได้โดยอัตโนมัติ ดังนั้นเราต้องใช้ verbose syntax (t("devise.forgot_password")) เพราะ dot syntax (t(".new_confirmation_mail")) จะไม่ทำงาน
หากคุณไปกับ active_record.*.yml มันสมเหตุสมผลที่จะรวบรวม keys ทั้งหมดที่มี active record scope เข้าไฟล์นั้น ย้าย Active Record keys จาก Rails *.yml files เข้า active_record.*.yml ที่ตรงกัน
เรายังมีสองคู่ของ *.yml files ที่ duplicate devise: scope พิจารณาผสม keys จาก Devise views เข้า devise.*.yml views นี่คือสิ่งที่ Devise-i18n gem ทำ และผมชอบ มันทำได้แบบนี้:
# mixing the view scopes into devise.nl.yml nl: devise: confirmations: ... registrations: ... edit: ... new: ...Some Tweaks and Tips
- ผมไม่ใช่แฟนของ header ใน error message ('x errors prohibited this user from being saved') ดังนั้นผมลบมันออกจาก
errorspartial - หากคุณตั้ง
default_localeเป็น:nlRails จะ 'humanize' keys หากหา translation ไม่เจอ ดังนั้นt(:some_untranslated_key)จะแสดงเป็นSome Untranslated Keyใน view - ด้วย I18n-tasks gem คุณสามารถ clean up unused keys และเพิ่ม missing keys มันเป็น tool ยอดเยี่ยม! อย่างไรก็ตาม IDE ของผมมี i18n support ที่ยอดเยี่ยม และสำหรับผมกลายเป็น workflow ที่เร็วกว่า gem
Parting Is Such Sweet Sorrow
คำสุดท้ายสั้นๆ ก่อนเราจะจากลา ตอนเริ่มต้นการเดินทางนี้ ผมไม่คาดหวังว่ามันจะเป็นงานมากขนาดนี้ ผมมีความสุขมากที่ตอนนี้ผมรู้ว่าความซับซ้อนมาจากไหน และอนาคตฉันและคุณตอนนี้มีรายการการเปลี่ยนแปลงที่จำเป็นทั้งหมด Woohoo!
แต่มากับ checklist นี้ในมือ คิดก่อนจะกระทำ: อาจจะคุ้มค่าที่จะทนกับ translations ที่ไม่ optimal ไปสักพัก…