2016-10-27 14 views
6

Tôi cần quốc tế hóa các chuỗi giao diện người dùng trong ứng dụng HTML ELM của tôi cho 3 ngôn ngữ khác nhau.Cách tốt để quốc tế hóa ứng dụng Elm là gì?

Tôi đang nghĩ đến việc làm điều này:

1) Tôi sẽ nhận được currentLanguage từ Javascript, và vượt qua nó xuống trong ProgramWithFlags. I'llkeep ngôn ngữ trong mô hình

2) Tôi sẽ thiết lập một số loại trong mã của tôi

type alias Languages = English | French | Spanish 
-- One of these for each string I want to internationalize 
type alias InternationalizedStrings = StringHello | StringFoo | StringBar 

3) Tôi sẽ làm một chức năng trả lại từng cụm từ dịch để sử dụng trong quan điểm của tôi.

getPhrase: InternationalizationString Languages -> string 
getPhrase stringId lang = 
    case lang of 
     English -> 
      case stringId of 
       StringHello -> "Hello" 
       StringFoo -> "Foo" 
       StringBar -> "Bar" 
     French -> 
      case stringId of 
       StringHello -> "Bonjour" 
       StringFoo -> "Oui" 
       StringBar -> "Non" 
     ... 

Có cách nào tốt hơn để thực hiện việc này không? Tôi có rất nhiều chuỗi.

+0

Điều bạn có thể làm là phân phối một loại kiểu nhất định dựa trên mã ngôn ngữ trong URL. Ví dụ, '/ fr/phrase' sẽ phục vụ frenchModel – DevNebulae

+1

Một lợi thế để sử dụng các kiểu union là mỗi thẻ có thể có các tham số. Bạn có thể có một thẻ 'StringHello String' cho biết bạn cần chỉ định tên người dùng, và nó được đánh mạnh theo cách mà tra cứu từ điển thông thường không thể. –

Trả lời

4

Trong trường hợp bạn muốn lỗi trình biên dịch khi bạn không cung cấp bản dịch cho chuỗi, giải pháp của bạn đang đi đúng hướng.

Nếu bạn muốn cho phép các chuỗi chưa được dịch hoặc thấy nó tẻ nhạt để có loại cho mọi chuỗi có thể dịch, bạn có thể muốn chuyển sang giải pháp dựa trên Dict. để tinker với nó, chỉ cần ném nó vào http://elm-lang.org/try:

import Dict exposing (Dict) 
import Html exposing (text) 


type Language 
    = English 
    | French 
    | Spanish 


type alias Key = 
    String 


main = 
    text <| translate French "Hello" 


translate : Language -> Key -> String 
translate lang key = 
    let 
     dict = 
      case lang of 
       English -> 
        Dict.fromList 
         [ ("Hello", "in english") 
         ] 

       French -> 
        Dict.fromList 
         [ ("Hello", "salut") 
         ] 

       Spanish -> 
        Dict.fromList 
         [ ("Hello", "hola") 
         , ("someKeyThatOnlyExistsInSpanish", "42") 
         ] 
    in 
     Dict.get key dict |> Maybe.withDefault ("can not find translation for " ++ key) 
2

Một thời gian trước, tôi đã có một vết nứt ở quốc tế, và đã đưa ra với các thiết lập sau:

  • xác định ngôn ngữ trong một toàn cầu model
  • có một chức năng rất đơn giản, được sử dụng trong view module và chức năng
  • chức năng có chữ ký của localString : Language -> String -> String
  • localString về cơ bản thực hiện tra cứu trong từ điển toàn cầu để tìm bản dịch từ từ bạn cung cấp cho ngôn ngữ bạn cung cấp.
  • nó sẽ luôn trả lại String, mặc định từ gốc, nếu nó không thể tìm thấy từ bạn cung cấp hoặc nếu nó không thể tìm thấy bản dịch sang ngôn ngữ bạn cung cấp.
  • giữ các chức năng từ điển (và trợ giúp) toàn cầu KHÔNG có trong mô hình, nhưng trong một tệp riêng biệt (nó là dữ liệu khá tĩnh, sẽ không thay đổi trong thời gian chạy).
  • loại Language là Loại liên minh, để đảm bảo chúng tôi chỉ có ngôn ngữ 'được phê duyệt'.
  • từ điển thực tế sử dụng chuyển đổi thành chuỗi. Loại Dict không cho phép loại mạnh làm khóa.

Bằng cách đó, sử dụng quốc tế có tác động tối thiểu trên phần còn lại của mã:

  • Bạn cần phải thêm một Language để bạn Model (mà bạn có thể nhận được thông qua cổng JS)
  • Bạn vẫn có thể sử dụng mã ngắn và dễ đọc trong chế độ xem của bạn để dịch, như

    p [] [ text <| localString model.language "car" ]

  • Tất cả các chuỗi được mã hóa cứng trong mã của riêng bạn vẫn còn bằng một ngôn ngữ mặc định đơn giản, để giữ cho phần còn lại của mã của bạn có thể đọc được.

Dưới đây là những ý chính về những gì tôi đã làm việc trên, bạn có thể sao chép/dán vào elm-lang.org/try (không kiểm tra đầy đủ chức năng hoặc hiệu suất-khôn ngoan với một số lượng lớn các chuỗi và bản dịch)

import Html exposing (div, p, text) 
import Dict exposing (Dict) 

-- Manage your languages below 

type Language = English | Spanish | French 

defaultLanguage : Language 
defaultLanguage = English 

languageToKey : Language -> LanguageKey 
languageToKey language = 
    case language of 
    English -> "English" 
    Spanish -> "Spanish" 
    French -> "French" 

keyToLanguage : LanguageKey -> Language 
keyToLanguage key = 
    case key of 
    "English" -> English 
    "Spanish"-> Spanish 
    "French" -> French 
    _ -> defaultLanguage 

english : LocalWord -> (Language, LocalWord) 
english word = 
    (English, word) 

spanish : LocalWord -> (Language, LocalWord) 
spanish word = 
    (Spanish, word) 

french : LocalWord -> (Language, LocalWord) 
french word = 
    (French, word) 

-- Internal stuff 

type alias Word = String 
type alias LocalWord = String 
type alias LanguageKey = String 

type alias Dictionary = Dict Word WordDict 
type alias WordDict = Dict LanguageKey LocalWord 

init : Dictionary 
init = 
    Dict.fromList [] 

newLocalWord : Word -> (Language, LocalWord) -> Maybe WordDict -> Maybe WordDict 
newLocalWord word (localLanguage, localWord) wordDict = 
    wordDict 
    |> Maybe.withDefault (Dict.fromList []) 
    |> Dict.insert (languageToKey defaultLanguage) word 
    |> Dict.insert (languageToKey localLanguage) localWord 
    |> Just 

addTranslation : Word -> (Language, LocalWord) -> Dictionary -> Dictionary 
addTranslation word newTranslation dictionary = 
    dictionary 
    |> Dict.update word (newLocalWord word newTranslation) 

localString : Language -> Word -> LocalWord 
localString language word = 
    let 
    wordEntry = 
     Dict.get word globalDictionary 
    localLanguage = 
     languageToKey language 
    in 
    case wordEntry of 
     Just wordDict -> 
     Dict.get localLanguage wordDict 
     |> Maybe.withDefault word 

     Nothing -> 
     word 

add : Word -> List (Language, LocalWord) -> Dictionary -> Dictionary 
add word translationList dictionary = 
    List.foldl (addTranslation word) dictionary translationList 

-- BUILD DICTIONARY BELOW 

globalDictionary : Dictionary 
globalDictionary = 
    init 
    |> add "Hello" [ spanish "Hola", french "Bonjour" ] 
    |> add "Man" [ spanish "Hombre", french "Homme" ] 
    |> add "Child" [ french "Enfant" ] 


-- For Elm-lang Try only 
localModel = 
    { language = Spanish } 

main = 
    div [] 
    [ p [] 
     [ text <| "Hello in Spanish: " 
     ++ localString localModel.language "Hello" 
     ] 
    , p [] 
     [ text <| "In dictionary, but not in Spanish: " 
     ++ localString localModel.language "Child" 
     ] 
    , p [] 
     [ text <| "Is not in dictionary: " 
     ++ localString localModel.language "Car" 
     ] 
    ] 
2

tôi đã viết một số blog post about this cách đây vài tháng. Nếu bạn có khả năng, hãy thử sử dụng ADT hơn Dict s kể từ Dict s không thể cung cấp cho bạn cùng một mức đảm bảo ở cấp loại (đó là lý do tại sao Dict.get trả về Maybe a). ADT cũng có thể có loại dữ liệu bạn đang hành động trên loại được chọn cũng như MyPhrase Int String mà bạn có thể khớp mẫu và sử dụng phương thức toString bạn muốn (ví dụ: MyPhrase foo bar -> "My phrase contains " ++ toString foo ++ " & " ++ bar ++ "."). Điều đó đang được nói, các hệ thống/dịch vụ dịch thuật hiện có có thể gây khó khăn cho việc sử dụng phương pháp này mà không cần viết một trình phân tích cú pháp từ .elm đến .json hoặc .po.

Các vấn đề liên quan