我需要将ELM HTML应用程序中的UI字符串国际化为3种不同的语言。
我正在考虑这样做:
1)我将从Javascript获取currentLanguage,并在ProgramWithFlags中传递它。我将保持模型中的语言
2)我将在我的代码中设置一些类型
type alias Languages = English | French | Spanish
-- One of these for each string I want to internationalize
type alias InternationalizedStrings = StringHello | StringFoo | StringBar
3)我将创建一个函数,用于返回在我的视图中使用的每个翻译短语。
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"
...
有更好的方法吗?我有很多字符串。
答案 0 :(得分:4)
如果您在没有为字符串提供翻译时想要编译错误,那么您的解决方案就在正确的轨道上。
如果您想要允许未翻译的字符串,或者发现每个可翻译字符串都有一个类型,那么您可能需要切换到基于Dict
的解决方案。修补它,把它扔进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)
答案 1 :(得分:2)
不久前,我在国际化方面遇到了麻烦,并提出了以下设置:
model
view
模块和功能localString : Language -> String -> String
localString
基本上在全球字典中查找,以便从您提供的字词到您提供的语言中找到翻译。String
,默认为原始字词。Language
类型是联盟类型,以确保我们只有“已批准”的语言。 Dict
类型不允许使用强类型作为密钥。这样,使用国际化对其余代码的影响最小:
Language
添加Model
(您可以通过JS端口获取)您仍然可以在视图中使用简短易读的代码进行翻译,例如
p [] [ text <| localString model.language "car" ]
您自己代码中的所有硬编码字符串都保留在一种简单的默认语言中,以保持代码的其余部分可读。
以下是我正在处理的内容,您可以复制/粘贴到elm-lang.org/try(未通过大量字符串和翻译在功能或性能方面进行全面测试)
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 :(得分:2)
几个月前我写了blog post about this。如果你有能力,试着优先使用Dict
以上的ADT,因为Dict
不能在类型级别给你相同的保证(这就是Dict.get
返回{{1}的原因}})。 ADT还可以将您正在执行类型检查的数据类型以及Maybe a
模式匹配,并使用您想要的任何MyPhrase Int String
方法(例如toString
)。话虽如此,现有的系统/翻译服务可能会在不编写从MyPhrase foo bar -> "My phrase contains " ++ toString foo ++ " & " ++ bar ++ "."
到.elm
或.json
的解析器的情况下难以使用此方法。