Browse Source

Add languageCode arg to translate & translateDeep, lowercase codes

Lowercasing the LanguageCode enums fits more closely the ISO 639-1 spec
Michael Bromley 7 years ago
parent
commit
65a0760fba

+ 3 - 0
modules/core/common/constants.ts

@@ -0,0 +1,3 @@
+import { LanguageCode } from '../locale/language-code';
+
+export const DEFAULT_LANGUAGE_CODE = LanguageCode.EN;

+ 184 - 184
modules/core/locale/language-code.graphql

@@ -1,371 +1,371 @@
 "ISO 639-1 language code"
 enum LanguageCode {
     "Afar"
-    AA
+    aa
     "Abkhazian"
-    AB
+    ab
     "Afrikaans"
-    AF
+    af
     "Akan"
-    AK
+    ak
     "Albanian"
-    SQ
+    sq
     "Amharic"
-    AM
+    am
     "Arabic"
-    AR
+    ar
     "Aragonese"
-    AN
+    an
     "Armenian"
-    HY
+    hy
     "Assamese"
-    AS
+    as
     "Avaric"
-    AV
+    av
     "Avestan"
-    AE
+    ae
     "Aymara"
-    AY
+    ay
     "Azerbaijani"
-    AZ
+    az
     "Bashkir"
-    BA
+    ba
     "Bambara"
-    BM
+    bm
     "Basque"
-    EU
+    eu
     "Belarusian"
-    BE
+    be
     "Bengali"
-    BN
+    bn
     "Bihari languages"
-    BH
+    bh
     "Bislama"
-    BI
+    bi
     "Bosnian"
-    BS
+    bs
     "Breton"
-    BR
+    br
     "Bulgarian"
-    BG
+    bg
     "Burmese"
-    MY
+    my
     "Catalan; Valencian"
-    CA
+    ca
     "Chamorro"
-    CH
+    ch
     "Chechen"
-    CE
+    ce
     "Chinese"
-    ZH
+    zh
     "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic"
-    CU
+    cu
     "Chuvash"
-    CV
+    cv
     "Cornish"
-    KW
+    kw
     "Corsican"
-    CO
+    co
     "Cree"
-    CR
+    cr
     "Czech"
-    CS
+    cs
     "Danish"
-    DA
+    da
     "Divehi; Dhivehi; Maldivian"
-    DV
+    dv
     "Dutch; Flemish"
-    NL
+    nl
     "Dzongkha"
-    DZ
+    dz
     "English"
-    EN
+    en
     "Esperanto"
-    EO
+    eo
     "Estonian"
-    ET
+    et
     "Ewe"
-    EE
+    ee
     "Faroese"
-    FO
+    fo
     "Fijian"
-    FJ
+    fj
     "Finnish"
-    FI
+    fi
     "French"
-    FR
+    fr
     "Western Frisian"
-    FY
+    fy
     "Fulah"
-    FF
+    ff
     "Georgian"
-    KA
+    ka
     "German"
-    DE
+    de
     "Gaelic; Scottish Gaelic"
-    GD
+    gd
     "Irish"
-    GA
+    ga
     "Galician"
-    GL
+    gl
     "Manx"
-    GV
+    gv
     "Greek, Modern (1453-)"
-    EL
+    el
     "Guarani"
-    GN
+    gn
     "Gujarati"
-    GU
+    gu
     "Haitian; Haitian Creole"
-    HT
+    ht
     "Hausa"
-    HA
+    ha
     "Hebrew"
-    HE
+    he
     "Herero"
-    HZ
+    hz
     "Hindi"
-    HI
+    hi
     "Hiri Motu"
-    HO
+    ho
     "Croatian"
-    HR
+    hr
     "Hungarian"
-    HU
+    hu
     "Igbo"
-    IG
+    ig
     "Icelandic"
-    IS
+    is
     "Ido"
-    IO
+    io
     "Sichuan Yi; Nuosu"
-    II
+    ii
     "Inuktitut"
-    IU
+    iu
     "Interlingue; Occidental"
-    IE
+    ie
     "Interlingua (International Auxiliary Language Association)"
-    IA
+    ia
     "Indonesian"
-    ID
+    id
     "Inupiaq"
-    IK
+    ik
     "Italian"
-    IT
+    it
     "Javanese"
-    JV
+    jv
     "Japanese"
-    JA
+    ja
     "Kalaallisut; Greenlandic"
-    KL
+    kl
     "Kannada"
-    KN
+    kn
     "Kashmiri"
-    KS
+    ks
     "Kanuri"
-    KR
+    kr
     "Kazakh"
-    KK
+    kk
     "Central Khmer"
-    KM
+    km
     "Kikuyu; Gikuyu"
-    KI
+    ki
     "Kinyarwanda"
-    RW
+    rw
     "Kirghiz; Kyrgyz"
-    KY
+    ky
     "Komi"
-    KV
+    kv
     "Kongo"
-    KG
+    kg
     "Korean"
-    KO
+    ko
     "Kuanyama; Kwanyama"
-    KJ
+    kj
     "Kurdish"
-    KU
+    ku
     "Lao"
-    LO
+    lo
     "Latin"
-    LA
+    la
     "Latvian"
-    LV
+    lv
     "Limburgan; Limburger; Limburgish"
-    LI
+    li
     "Lingala"
-    LN
+    ln
     "Lithuanian"
-    LT
+    lt
     "Luxembourgish; Letzeburgesch"
-    LB
+    lb
     "Luba-Katanga"
-    LU
+    lu
     "Ganda"
-    LG
+    lg
     "Macedonian"
-    MK
+    mk
     "Marshallese"
-    MH
+    mh
     "Malayalam"
-    ML
+    ml
     "Maori"
-    MI
+    mi
     "Marathi"
-    MR
+    mr
     "Malay"
-    MS
+    ms
     "Malagasy"
-    MG
+    mg
     "Maltese"
-    MT
+    mt
     "Mongolian"
-    MN
+    mn
     "Nauru"
-    NA
+    na
     "Navajo; Navaho"
-    NV
+    nv
     "Ndebele, South; South Ndebele"
-    NR
+    nr
     "Ndebele, North; North Ndebele"
-    ND
+    nd
     "Ndonga"
-    NG
+    ng
     "Nepali"
-    NE
+    ne
     "Norwegian Nynorsk; Nynorsk, Norwegian"
-    NN
+    nn
     "Bokmål, Norwegian; Norwegian Bokmål"
-    NB
+    nb
     "Norwegian"
-    NO
+    no
     "Chichewa; Chewa; Nyanja"
-    NY
+    ny
     "Occitan (post 1500); Provençal"
-    OC
+    oc
     "Ojibwa"
-    OJ
+    oj
     "Oriya"
-    OR
+    or
     "Oromo"
-    OM
+    om
     "Ossetian; Ossetic"
-    OS
+    os
     "Panjabi; Punjabi"
-    PA
+    pa
     "Persian"
-    FA
+    fa
     "Pali"
-    PI
+    pi
     "Polish"
-    PL
+    pl
     "Portuguese"
-    PT
+    pt
     "Pushto; Pashto"
-    PS
+    ps
     "Quechua"
-    QU
+    qu
     "Romansh"
-    RM
+    rm
     "Romanian; Moldavian; Moldovan"
-    RO
+    ro
     "Rundi"
-    RN
+    rn
     "Russian"
-    RU
+    ru
     "Sango"
-    SG
+    sg
     "Sanskrit"
-    SA
+    sa
     "Sinhala; Sinhalese"
-    SI
+    si
     "Slovak"
-    SK
+    sk
     "Slovenian"
-    SL
+    sl
     "Northern Sami"
-    SE
+    se
     "Samoan"
-    SM
+    sm
     "Shona"
-    SN
+    sn
     "Sindhi"
-    SD
+    sd
     "Somali"
-    SO
+    so
     "Sotho, Southern"
-    ST
+    st
     "Spanish; Castilian"
-    ES
+    es
     "Sardinian"
-    SC
+    sc
     "Serbian"
-    SR
+    sr
     "Swati"
-    SS
+    ss
     "Sundanese"
-    SU
+    su
     "Swahili"
-    SW
+    sw
     "Swedish"
-    SV
+    sv
     "Tahitian"
-    TY
+    ty
     "Tamil"
-    TA
+    ta
     "Tatar"
-    TT
+    tt
     "Telugu"
-    TE
+    te
     "Tajik"
-    TG
+    tg
     "Tagalog"
-    TL
+    tl
     "Thai"
-    TH
+    th
     "Tibetan"
-    BO
+    bo
     "Tigrinya"
-    TI
+    ti
     "Tonga (Tonga Islands)"
-    TO
+    to
     "Tswana"
-    TN
+    tn
     "Tsonga"
-    TS
+    ts
     "Turkmen"
-    TK
+    tk
     "Turkish"
-    TR
+    tr
     "Twi"
-    TW
+    tw
     "Uighur; Uyghur"
-    UG
+    ug
     "Ukrainian"
-    UK
+    uk
     "Urdu"
-    UR
+    ur
     "Uzbek"
-    UZ
+    uz
     "Venda"
-    VE
+    ve
     "Vietnamese"
-    VI
+    vi
     "Volapük"
-    VO
+    vo
     "Welsh"
-    CY
+    cy
     "Walloon"
-    WA
+    wa
     "Wolof"
-    WO
+    wo
     "Xhosa"
-    XH
+    xh
     "Yiddish"
-    YI
+    yi
     "Yoruba"
-    YO
+    yo
     "Zhuang; Chuang"
-    ZA
+    za
     "Zulu"
-    ZU
+    zu
 }

+ 184 - 184
modules/core/locale/language-code.ts

@@ -2,188 +2,188 @@
  * ISO 639-1 language codes (https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
  */
 export enum LanguageCode {
-    AA = 'AA', // Afar
-    AB = 'AB', // Abkhazian
-    AF = 'AF', // Afrikaans
-    AK = 'AK', // Akan
-    SQ = 'SQ', // Albanian
-    AM = 'AM', // Amharic
-    AR = 'AR', // Arabic
-    AN = 'AN', // Aragonese
-    HY = 'HY', // Armenian
-    AS = 'AS', // Assamese
-    AV = 'AV', // Avaric
-    AE = 'AE', // Avestan
-    AY = 'AY', // Aymara
-    AZ = 'AZ', // Azerbaijani
-    BA = 'BA', // Bashkir
-    BM = 'BM', // Bambara
-    EU = 'EU', // Basque
-    BE = 'BE', // Belarusian
-    BN = 'BN', // Bengali
-    BH = 'BH', // Bihari languages
-    BI = 'BI', // Bislama
-    BS = 'BS', // Bosnian
-    BR = 'BR', // Breton
-    BG = 'BG', // Bulgarian
-    MY = 'MY', // Burmese
-    CA = 'CA', // Catalan; Valencian
-    CH = 'CH', // Chamorro
-    CE = 'CE', // Chechen
-    ZH = 'ZH', // Chinese
-    CU = 'CU', // Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic
-    CV = 'CV', // Chuvash
-    KW = 'KW', // Cornish
-    CO = 'CO', // Corsican
-    CR = 'CR', // Cree
-    CS = 'CS', // Czech
-    DA = 'DA', // Danish
-    DV = 'DV', // Divehi; Dhivehi; Maldivian
-    NL = 'NL', // Dutch; Flemish
-    DZ = 'DZ', // Dzongkha
-    EN = 'EN', // English
-    EO = 'EO', // Esperanto
-    ET = 'ET', // Estonian
-    EE = 'EE', // Ewe
-    FO = 'FO', // Faroese
-    FJ = 'FJ', // Fijian
-    FI = 'FI', // Finnish
-    FR = 'FR', // French
-    FY = 'FY', // Western Frisian
-    FF = 'FF', // Fulah
-    KA = 'KA', // Georgian
-    DE = 'DE', // German
-    GD = 'GD', // Gaelic; Scottish Gaelic
-    GA = 'GA', // Irish
-    GL = 'GL', // Galician
-    GV = 'GV', // Manx
-    EL = 'EL', // Greek, Modern (1453-)
-    GN = 'GN', // Guarani
-    GU = 'GU', // Gujarati
-    HT = 'HT', // Haitian; Haitian Creole
-    HA = 'HA', // Hausa
-    HE = 'HE', // Hebrew
-    HZ = 'HZ', // Herero
-    HI = 'HI', // Hindi
-    HO = 'HO', // Hiri Motu
-    HR = 'HR', // Croatian
-    HU = 'HU', // Hungarian
-    IG = 'IG', // Igbo
-    IS = 'IS', // Icelandic
-    IO = 'IO', // Ido
-    II = 'II', // Sichuan Yi; Nuosu
-    IU = 'IU', // Inuktitut
-    IE = 'IE', // Interlingue; Occidental
-    IA = 'IA', // Interlingua (International Auxiliary Language Association)
-    ID = 'ID', // Indonesian
-    IK = 'IK', // Inupiaq
-    IT = 'IT', // Italian
-    JV = 'JV', // Javanese
-    JA = 'JA', // Japanese
-    KL = 'KL', // Kalaallisut; Greenlandic
-    KN = 'KN', // Kannada
-    KS = 'KS', // Kashmiri
-    KR = 'KR', // Kanuri
-    KK = 'KK', // Kazakh
-    KM = 'KM', // Central Khmer
-    KI = 'KI', // Kikuyu; Gikuyu
-    RW = 'RW', // Kinyarwanda
-    KY = 'KY', // Kirghiz; Kyrgyz
-    KV = 'KV', // Komi
-    KG = 'KG', // Kongo
-    KO = 'KO', // Korean
-    KJ = 'KJ', // Kuanyama; Kwanyama
-    KU = 'KU', // Kurdish
-    LO = 'LO', // Lao
-    LA = 'LA', // Latin
-    LV = 'LV', // Latvian
-    LI = 'LI', // Limburgan; Limburger; Limburgish
-    LN = 'LN', // Lingala
-    LT = 'LT', // Lithuanian
-    LB = 'LB', // Luxembourgish; Letzeburgesch
-    LU = 'LU', // Luba-Katanga
-    LG = 'LG', // Ganda
-    MK = 'MK', // Macedonian
-    MH = 'MH', // Marshallese
-    ML = 'ML', // Malayalam
-    MI = 'MI', // Maori
-    MR = 'MR', // Marathi
-    MS = 'MS', // Malay
-    MG = 'MG', // Malagasy
-    MT = 'MT', // Maltese
-    MN = 'MN', // Mongolian
-    NA = 'NA', // Nauru
-    NV = 'NV', // Navajo; Navaho
-    NR = 'NR', // Ndebele, South; South Ndebele
-    ND = 'ND', // Ndebele, North; North Ndebele
-    NG = 'NG', // Ndonga
-    NE = 'NE', // Nepali
-    NN = 'NN', // Norwegian Nynorsk; Nynorsk, Norwegian
-    NB = 'NB', // Bokmål, Norwegian; Norwegian Bokmål
-    NO = 'NO', // Norwegian
-    NY = 'NY', // Chichewa; Chewa; Nyanja
-    OC = 'OC', // Occitan (post 1500); Provençal
-    OJ = 'OJ', // Ojibwa
-    OR = 'OR', // Oriya
-    OM = 'OM', // Oromo
-    OS = 'OS', // Ossetian; Ossetic
-    PA = 'PA', // Panjabi; Punjabi
-    FA = 'FA', // Persian
-    PI = 'PI', // Pali
-    PL = 'PL', // Polish
-    PT = 'PT', // Portuguese
-    PS = 'PS', // Pushto; Pashto
-    QU = 'QU', // Quechua
-    RM = 'RM', // Romansh
-    RO = 'RO', // Romanian; Moldavian; Moldovan
-    RN = 'RN', // Rundi
-    RU = 'RU', // Russian
-    SG = 'SG', // Sango
-    SA = 'SA', // Sanskrit
-    SI = 'SI', // Sinhala; Sinhalese
-    SK = 'SK', // Slovak
-    SL = 'SL', // Slovenian
-    SE = 'SE', // Northern Sami
-    SM = 'SM', // Samoan
-    SN = 'SN', // Shona
-    SD = 'SD', // Sindhi
-    SO = 'SO', // Somali
-    ST = 'ST', // Sotho, Southern
-    ES = 'ES', // Spanish; Castilian
-    SC = 'SC', // Sardinian
-    SR = 'SR', // Serbian
-    SS = 'SS', // Swati
-    SU = 'SU', // Sundanese
-    SW = 'SW', // Swahili
-    SV = 'SV', // Swedish
-    TY = 'TY', // Tahitian
-    TA = 'TA', // Tamil
-    TT = 'TT', // Tatar
-    TE = 'TE', // Telugu
-    TG = 'TG', // Tajik
-    TL = 'TL', // Tagalog
-    TH = 'TH', // Thai
-    BO = 'BO', // Tibetan
-    TI = 'TI', // Tigrinya
-    TO = 'TO', // Tonga (Tonga Islands)
-    TN = 'TN', // Tswana
-    TS = 'TS', // Tsonga
-    TK = 'TK', // Turkmen
-    TR = 'TR', // Turkish
-    TW = 'TW', // Twi
-    UG = 'UG', // Uighur; Uyghur
-    UK = 'UK', // Ukrainian
-    UR = 'UR', // Urdu
-    UZ = 'UZ', // Uzbek
-    VE = 'VE', // Venda
-    VI = 'VI', // Vietnamese
-    VO = 'VO', // Volapük
-    CY = 'CY', // Welsh
-    WA = 'WA', // Walloon
-    WO = 'WO', // Wolof
-    XH = 'XH', // Xhosa
-    YI = 'YI', // Yiddish
-    YO = 'YO', // Yoruba
-    ZA = 'ZA', // Zhuang; Chuang
-    ZU = 'ZU', // Zulu
+    AA = 'aa', // Afar
+    AB = 'ab', // Abkhazian
+    AF = 'af', // Afrikaans
+    AK = 'ak', // Akan
+    SQ = 'sq', // Albanian
+    AM = 'am', // Amharic
+    AR = 'ar', // Arabic
+    AN = 'an', // Aragonese
+    HY = 'hy', // Armenian
+    AS = 'as', // Assamese
+    AV = 'av', // Avaric
+    AE = 'ae', // Avestan
+    AY = 'ay', // Aymara
+    AZ = 'az', // Azerbaijani
+    BA = 'ba', // Bashkir
+    BM = 'bm', // Bambara
+    EU = 'eu', // Basque
+    BE = 'be', // Belarusian
+    BN = 'bn', // Bengali
+    BH = 'bh', // Bihari languages
+    BI = 'bi', // Bislama
+    BS = 'bs', // Bosnian
+    BR = 'br', // Breton
+    BG = 'bg', // Bulgarian
+    MY = 'my', // Burmese
+    CA = 'ca', // Catalan; Valencian
+    CH = 'ch', // Chamorro
+    CE = 'ce', // Chechen
+    ZH = 'zh', // Chinese
+    CU = 'cu', // Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic
+    CV = 'cv', // Chuvash
+    KW = 'kw', // Cornish
+    CO = 'co', // Corsican
+    CR = 'cr', // Cree
+    CS = 'cs', // Czech
+    DA = 'da', // Danish
+    DV = 'dv', // Divehi; Dhivehi; Maldivian
+    NL = 'nl', // Dutch; Flemish
+    DZ = 'dz', // Dzongkha
+    EN = 'en', // English
+    EO = 'eo', // Esperanto
+    ET = 'et', // Estonian
+    EE = 'ee', // Ewe
+    FO = 'fo', // Faroese
+    FJ = 'fj', // Fijian
+    FI = 'fi', // Finnish
+    FR = 'fr', // French
+    FY = 'fy', // Western Frisian
+    FF = 'ff', // Fulah
+    KA = 'ka', // Georgian
+    DE = 'de', // German
+    GD = 'gd', // Gaelic; Scottish Gaelic
+    GA = 'ga', // Irish
+    GL = 'gl', // Galician
+    GV = 'gv', // Manx
+    EL = 'el', // Greek, Modern (1453-)
+    GN = 'gn', // Guarani
+    GU = 'gu', // Gujarati
+    HT = 'ht', // Haitian; Haitian Creole
+    HA = 'ha', // Hausa
+    HE = 'he', // Hebrew
+    HZ = 'hz', // Herero
+    HI = 'hi', // Hindi
+    HO = 'ho', // Hiri Motu
+    HR = 'hr', // Croatian
+    HU = 'hu', // Hungarian
+    IG = 'ig', // Igbo
+    IS = 'is', // Icelandic
+    IO = 'io', // Ido
+    II = 'ii', // Sichuan Yi; Nuosu
+    IU = 'iu', // Inuktitut
+    IE = 'ie', // Interlingue; Occidental
+    IA = 'ia', // Interlingua (International Auxiliary Language Association)
+    ID = 'id', // Indonesian
+    IK = 'ik', // Inupiaq
+    IT = 'it', // Italian
+    JV = 'jv', // Javanese
+    JA = 'ja', // Japanese
+    KL = 'kl', // Kalaallisut; Greenlandic
+    KN = 'kn', // Kannada
+    KS = 'ks', // Kashmiri
+    KR = 'kr', // Kanuri
+    KK = 'kk', // Kazakh
+    KM = 'km', // Central Khmer
+    KI = 'ki', // Kikuyu; Gikuyu
+    RW = 'rw', // Kinyarwanda
+    KY = 'ky', // Kirghiz; Kyrgyz
+    KV = 'kv', // Komi
+    KG = 'kg', // Kongo
+    KO = 'ko', // Korean
+    KJ = 'kj', // Kuanyama; Kwanyama
+    KU = 'ku', // Kurdish
+    LO = 'lo', // Lao
+    LA = 'la', // Latin
+    LV = 'lv', // Latvian
+    LI = 'li', // Limburgan; Limburger; Limburgish
+    LN = 'ln', // Lingala
+    LT = 'lt', // Lithuanian
+    LB = 'lb', // Luxembourgish; Letzeburgesch
+    LU = 'lu', // Luba-Katanga
+    LG = 'lg', // Ganda
+    MK = 'mk', // Macedonian
+    MH = 'mh', // Marshallese
+    ML = 'ml', // Malayalam
+    MI = 'mi', // Maori
+    MR = 'mr', // Marathi
+    MS = 'ms', // Malay
+    MG = 'mg', // Malagasy
+    MT = 'mt', // Maltese
+    MN = 'mn', // Mongolian
+    NA = 'na', // Nauru
+    NV = 'nv', // Navajo; Navaho
+    NR = 'nr', // Ndebele, South; South Ndebele
+    ND = 'nd', // Ndebele, North; North Ndebele
+    NG = 'ng', // Ndonga
+    NE = 'ne', // Nepali
+    NN = 'nn', // Norwegian Nynorsk; Nynorsk, Norwegian
+    NB = 'nb', // Bokmål, Norwegian; Norwegian Bokmål
+    NO = 'no', // Norwegian
+    NY = 'ny', // Chichewa; Chewa; Nyanja
+    OC = 'oc', // Occitan (post 1500); Provençal
+    OJ = 'oj', // Ojibwa
+    OR = 'or', // Oriya
+    OM = 'om', // Oromo
+    OS = 'os', // Ossetian; Ossetic
+    PA = 'pa', // Panjabi; Punjabi
+    FA = 'fa', // Persian
+    PI = 'pi', // Pali
+    PL = 'pl', // Polish
+    PT = 'pt', // Portuguese
+    PS = 'ps', // Pushto; Pashto
+    QU = 'qu', // Quechua
+    RM = 'rm', // Romansh
+    RO = 'ro', // Romanian; Moldavian; Moldovan
+    RN = 'rn', // Rundi
+    RU = 'ru', // Russian
+    SG = 'sg', // Sango
+    SA = 'sa', // Sanskrit
+    SI = 'si', // Sinhala; Sinhalese
+    SK = 'sk', // Slovak
+    SL = 'sl', // Slovenian
+    SE = 'se', // Northern Sami
+    SM = 'sm', // Samoan
+    SN = 'sn', // Shona
+    SD = 'sd', // Sindhi
+    SO = 'so', // Somali
+    ST = 'st', // Sotho, Southern
+    ES = 'es', // Spanish; Castilian
+    SC = 'sc', // Sardinian
+    SR = 'sr', // Serbian
+    SS = 'ss', // Swati
+    SU = 'su', // Sundanese
+    SW = 'sw', // Swahili
+    SV = 'sv', // Swedish
+    TY = 'ty', // Tahitian
+    TA = 'ta', // Tamil
+    TT = 'tt', // Tatar
+    TE = 'te', // Telugu
+    TG = 'tg', // Tajik
+    TL = 'tl', // Tagalog
+    TH = 'th', // Thai
+    BO = 'bo', // Tibetan
+    TI = 'ti', // Tigrinya
+    TO = 'to', // Tonga (Tonga Islands)
+    TN = 'tn', // Tswana
+    TS = 'ts', // Tsonga
+    TK = 'tk', // Turkmen
+    TR = 'tr', // Turkish
+    TW = 'tw', // Twi
+    UG = 'ug', // Uighur; Uyghur
+    UK = 'uk', // Ukrainian
+    UR = 'ur', // Urdu
+    UZ = 'uz', // Uzbek
+    VE = 've', // Venda
+    VI = 'vi', // Vietnamese
+    VO = 'vo', // Volapük
+    CY = 'cy', // Welsh
+    WA = 'wa', // Walloon
+    WO = 'wo', // Wolof
+    XH = 'xh', // Xhosa
+    YI = 'yi', // Yiddish
+    YO = 'yo', // Yoruba
+    ZA = 'za', // Zhuang; Chuang
+    ZU = 'zu', // Zulu
 }

+ 70 - 39
modules/core/locale/translate-entity.spec.ts

@@ -9,48 +9,79 @@ import { Translatable, Translation } from './locale-types';
 import { translateDeep, translateEntity } from './translate-entity';
 
 const LANGUAGE_CODE = LanguageCode.EN;
-const PRODUCT_NAME = 'English Name';
-const VARIANT_NAME = 'English Variant';
-const OPTION_NAME = 'English Option';
+const PRODUCT_NAME_EN = 'English Name';
+const VARIANT_NAME_EN = 'English Variant';
+const OPTION_NAME_EN = 'English Option';
+const PRODUCT_NAME_DE = 'German Name';
+const VARIANT_NAME_DE = 'German Variant';
+const OPTION_NAME_DE = 'German Option';
 
 describe('translateEntity()', () => {
     let product: Product;
-    let productTranslation: ProductTranslation;
+    let productTranslationEN: ProductTranslation;
+    let productTranslationDE: ProductTranslation;
 
     beforeEach(() => {
-        productTranslation = new ProductTranslation();
-        productTranslation.id = 2;
-        productTranslation.languageCode = LANGUAGE_CODE;
-        productTranslation.name = PRODUCT_NAME;
+        productTranslationEN = new ProductTranslation({
+            id: 2,
+            languageCode: LanguageCode.EN,
+            name: PRODUCT_NAME_EN,
+            slug: '',
+            description: '',
+        });
+        productTranslationEN.base = { id: 1 } as any;
+
+        productTranslationDE = new ProductTranslation({
+            id: 3,
+            languageCode: LanguageCode.DE,
+            name: PRODUCT_NAME_DE,
+            slug: '',
+            description: '',
+        });
+        productTranslationDE.base = { id: 1 } as any;
 
         product = new Product();
         product.id = 1;
-        product.translations = [productTranslation];
+        product.translations = [productTranslationEN, productTranslationDE];
     });
 
-    it('should unwrap the first translation', () => {
-        const result = translateEntity(product);
+    it('should unwrap the matching translation', () => {
+        const result = translateEntity(product, LanguageCode.EN);
 
-        expect(result).toHaveProperty('name', PRODUCT_NAME);
+        expect(result).toHaveProperty('name', PRODUCT_NAME_EN);
     });
 
     it('should not overwrite translatable id with translation id', () => {
-        const result = translateEntity(product);
+        const result = translateEntity(product, LanguageCode.EN);
 
         expect(result).toHaveProperty('id', 1);
     });
 
-    it('should not transfer the languageCode from the translation', () => {
-        const result = translateEntity(product);
+    it('should note transfer the base from the selected translation', () => {
+        const result = translateEntity(product, LanguageCode.EN);
 
-        expect(result).not.toHaveProperty('languageCode');
+        expect(result).not.toHaveProperty('base');
+    });
+
+    it('should transfer the languageCode from the selected translation', () => {
+        const result = translateEntity(product, LanguageCode.EN);
+
+        expect(result).toHaveProperty('languageCode', 'en');
     });
 
     it('throw if there are no translations available', () => {
         product.translations = [];
 
-        expect(() => translateEntity(product)).toThrow(
-            'Translatable entity "Product" has not been translated into the requested language',
+        expect(() => translateEntity(product, LanguageCode.EN)).toThrow(
+            'Translatable entity "Product" has not been translated into the requested language (en)',
+        );
+    });
+
+    it('throw if the desired translation is not available', () => {
+        product.translations = [];
+
+        expect(() => translateEntity(product, LanguageCode.ZU)).toThrow(
+            'Translatable entity "Product" has not been translated into the requested language (zu)',
         );
     });
 });
@@ -91,12 +122,12 @@ describe('translateDeep()', () => {
         productTranslation = new ProductTranslation();
         productTranslation.id = 2;
         productTranslation.languageCode = LANGUAGE_CODE;
-        productTranslation.name = PRODUCT_NAME;
+        productTranslation.name = PRODUCT_NAME_EN;
 
         productOptionTranslation = new ProductOptionTranslation();
         productOptionTranslation.id = 31;
         productOptionTranslation.languageCode = LANGUAGE_CODE;
-        productOptionTranslation.name = OPTION_NAME;
+        productOptionTranslation.name = OPTION_NAME_EN;
 
         productOption = new ProductOption();
         productOption.id = 3;
@@ -105,7 +136,7 @@ describe('translateDeep()', () => {
         productVariantTranslation = new ProductVariantTranslationEntity();
         productVariantTranslation.id = 41;
         productVariantTranslation.languageCode = LANGUAGE_CODE;
-        productVariantTranslation.name = VARIANT_NAME;
+        productVariantTranslation.name = VARIANT_NAME_EN;
 
         productVariant = new ProductVariant();
         productVariant.id = 3;
@@ -126,55 +157,55 @@ describe('translateDeep()', () => {
     });
 
     it('should translate the root entity', () => {
-        const result = translateDeep(product);
+        const result = translateDeep(product, LanguageCode.EN);
 
-        expect(result).toHaveProperty('name', PRODUCT_NAME);
+        expect(result).toHaveProperty('name', PRODUCT_NAME_EN);
     });
 
     it('should not throw if root entity has no translations', () => {
-        expect(() => translateDeep(testProduct)).not.toThrow();
+        expect(() => translateDeep(testProduct, LanguageCode.EN)).not.toThrow();
     });
 
     it('should not throw if first-level nested entity is not defined', () => {
         testProduct.singleRealVariant = undefined as any;
-        expect(() => translateDeep(testProduct, ['singleRealVariant'])).not.toThrow();
+        expect(() => translateDeep(testProduct, LanguageCode.EN, ['singleRealVariant'])).not.toThrow();
     });
 
     it('should not throw if second-level nested entity is not defined', () => {
         testProduct.singleRealVariant.options = undefined as any;
-        expect(() => translateDeep(testProduct, [['singleRealVariant', 'options']])).not.toThrow();
+        expect(() => translateDeep(testProduct, LanguageCode.EN, [['singleRealVariant', 'options']])).not.toThrow();
     });
 
     it('should translate a first-level nested non-array entity', () => {
-        const result = translateDeep(testProduct, ['singleRealVariant']);
+        const result = translateDeep(testProduct, LanguageCode.EN, ['singleRealVariant']);
 
-        expect(result.singleRealVariant).toHaveProperty('name', VARIANT_NAME);
+        expect(result.singleRealVariant).toHaveProperty('name', VARIANT_NAME_EN);
     });
 
     it('should translate a first-level nested entity array', () => {
-        const result = translateDeep(product, ['variants']);
+        const result = translateDeep(product, LanguageCode.EN, ['variants']);
 
-        expect(result).toHaveProperty('name', PRODUCT_NAME);
-        expect(result.variants[0]).toHaveProperty('name', VARIANT_NAME);
+        expect(result).toHaveProperty('name', PRODUCT_NAME_EN);
+        expect(result.variants[0]).toHaveProperty('name', VARIANT_NAME_EN);
     });
 
     it('should translate a second-level nested non-array entity', () => {
-        const result = translateDeep(testProduct, [['singleTestVariant', 'singleOption']]);
+        const result = translateDeep(testProduct, LanguageCode.EN, [['singleTestVariant', 'singleOption']]);
 
-        expect(result.singleTestVariant.singleOption).toHaveProperty('name', OPTION_NAME);
+        expect(result.singleTestVariant.singleOption).toHaveProperty('name', OPTION_NAME_EN);
     });
 
     it('should translate a second-level nested entity array (first-level is not array)', () => {
-        const result = translateDeep(testProduct, [['singleRealVariant', 'options']]);
+        const result = translateDeep(testProduct, LanguageCode.EN, [['singleRealVariant', 'options']]);
 
-        expect(result.singleRealVariant.options[0]).toHaveProperty('name', OPTION_NAME);
+        expect(result.singleRealVariant.options[0]).toHaveProperty('name', OPTION_NAME_EN);
     });
 
     it('should translate a second-level nested entity array', () => {
-        const result = translateDeep(product, ['variants', ['variants', 'options']]);
+        const result = translateDeep(product, LanguageCode.EN, ['variants', ['variants', 'options']]);
 
-        expect(result).toHaveProperty('name', PRODUCT_NAME);
-        expect(result.variants[0]).toHaveProperty('name', VARIANT_NAME);
-        expect(result.variants[0].options[0]).toHaveProperty('name', OPTION_NAME);
+        expect(result).toHaveProperty('name', PRODUCT_NAME_EN);
+        expect(result.variants[0]).toHaveProperty('name', VARIANT_NAME_EN);
+        expect(result.variants[0].options[0]).toHaveProperty('name', OPTION_NAME_EN);
     });
 });

+ 17 - 14
modules/core/locale/translate-entity.ts

@@ -1,3 +1,4 @@
+import { LanguageCode } from './language-code';
 import { Translatable } from './locale-types';
 
 // prettier-ignore
@@ -29,23 +30,24 @@ export class NotTranslatedError extends Error {}
 
 /**
  * Converts a Translatable entity into the public-facing entity by unwrapping
- * the translated strings from the first of the Translation entities.
+ * the translated strings from the matching Translation entity.
  */
-export function translateEntity<T extends Translatable>(translatable: T): T {
-    if (!translatable.translations || translatable.translations.length === 0) {
+export function translateEntity<T extends Translatable>(translatable: T, languageCode: LanguageCode): T {
+    const translation =
+        translatable.translations && translatable.translations.find(t => t.languageCode === languageCode);
+
+    if (!translation) {
         throw new NotTranslatedError(
             `Translatable entity "${
                 translatable.constructor.name
-            }" has not been translated into the requested language`,
+            }" has not been translated into the requested language (${languageCode})`,
         );
     }
-    const translation = translatable.translations[0];
 
     const translated = { ...(translatable as any) };
-    // delete translated.translations;
 
     for (const [key, value] of Object.entries(translation)) {
-        if (key !== 'languageCode' && key !== 'id') {
+        if (key !== 'base' && key !== 'id') {
             translated[key] = value;
         }
     }
@@ -57,11 +59,12 @@ export function translateEntity<T extends Translatable>(translatable: T): T {
  */
 export function translateDeep<T extends Translatable>(
     translatable: T,
+    languageCode: LanguageCode,
     translatableRelations: DeepTranslatableRelations<T> = [],
 ): T {
     let translatedEntity: T;
     try {
-        translatedEntity = translateEntity(translatable);
+        translatedEntity = translateEntity(translatable, languageCode);
     } catch (e) {
         translatedEntity = translatable as any;
     }
@@ -79,17 +82,17 @@ export function translateDeep<T extends Translatable>(
                 valueLevel0.forEach((nested1, index) => {
                     object = translatedEntity[path0][index];
                     property = path1;
-                    value = translateLeaf(object, property);
+                    value = translateLeaf(object, property, languageCode);
                 });
             } else {
                 object = translatedEntity[path0];
                 property = path1;
-                value = translateLeaf(object, property);
+                value = translateLeaf(object, property, languageCode);
             }
         } else {
             object = translatedEntity;
             property = path as any;
-            value = translateLeaf(object, property);
+            value = translateLeaf(object, property, languageCode);
         }
         if (object && property!) {
             object[property] = value;
@@ -99,11 +102,11 @@ export function translateDeep<T extends Translatable>(
     return translatedEntity;
 }
 
-function translateLeaf(object: any, property: string): any {
+function translateLeaf(object: any, property: string, languageCode: LanguageCode): any {
     if (Array.isArray(object[property])) {
-        return object[property].map(nested2 => translateEntity(nested2));
+        return object[property].map(nested2 => translateEntity(nested2, languageCode));
     } else if (object[property]) {
-        return translateEntity(object[property]);
+        return translateEntity(object[property], languageCode);
     } else {
         return undefined;
     }

+ 2 - 1
modules/core/service/product-variant.service.ts

@@ -1,6 +1,7 @@
 import { Injectable } from '@nestjs/common';
 import { InjectConnection } from '@nestjs/typeorm';
 import { Connection } from 'typeorm';
+import { DEFAULT_LANGUAGE_CODE } from '../common/constants';
 import { ProductOption } from '../entity/product-option/product-option.entity';
 import { CreateProductVariantDto } from '../entity/product-variant/create-product-variant.dto';
 import { ProductVariantTranslationEntity } from '../entity/product-variant/product-variant-translation.entity';
@@ -39,6 +40,6 @@ export class ProductVariantService {
         return this.connection
             .getCustomRepository(ProductVariantRepository)
             .create(product, productVariant, variantTranslations)
-            .then(variant => translateDeep(variant));
+            .then(variant => translateDeep(variant, DEFAULT_LANGUAGE_CODE));
     }
 }

+ 17 - 14
modules/core/service/product.service.ts

@@ -1,6 +1,7 @@
 import { Injectable } from '@nestjs/common';
 import { InjectConnection } from '@nestjs/typeorm';
 import { Connection } from 'typeorm';
+import { DEFAULT_LANGUAGE_CODE } from '../common/constants';
 import { foundIn, not } from '../common/utils';
 import { ProductOptionGroup } from '../entity/product-option-group/product-option-group.entity';
 import { ProductTranslation } from '../entity/product/product-translation.entity';
@@ -19,14 +20,21 @@ export class ProductService {
         return this.connection
             .getCustomRepository(ProductRepository)
             .find(lang)
-            .then(products => products.map(product => this.translateProductEntity(product)));
+            .then(products =>
+                products.map(product =>
+                    translateDeep(product, lang, ['optionGroups', 'variants', ['variants', 'options']]),
+                ),
+            );
     }
 
     findOne(productId: number, lang: LanguageCode): Promise<Product | undefined> {
         return this.connection
             .getCustomRepository(ProductRepository)
             .findOne(productId, lang)
-            .then(product => product && this.translateProductEntity(product));
+            .then(
+                product =>
+                    product && translateDeep(product, lang, ['optionGroups', 'variants', ['variants', 'options']]),
+            );
     }
 
     async create(createProductDto: CreateProductDto): Promise<Product> {
@@ -47,18 +55,16 @@ export class ProductService {
         return this.connection
             .getCustomRepository(ProductRepository)
             .create(product, productTranslations)
-            .then(createdProduct => translateDeep(createdProduct));
+            .then(createdProduct => translateDeep(createdProduct, DEFAULT_LANGUAGE_CODE));
     }
 
-    async update(updateProductDto: UpdateProductDto): Promise<Product> {
+    async update(updateProductDto: UpdateProductDto): Promise<Product | undefined> {
         const { optionGroupCodes, image, translations } = updateProductDto;
         const productTranslations: ProductTranslation[] = [];
 
         // get current translations
         const existingTranslations = await this.connection.getRepository(ProductTranslation).find({
-            where: {
-                base: updateProductDto.id,
-            },
+            where: { base: updateProductDto.id },
             relations: ['base'],
         });
 
@@ -68,10 +74,11 @@ export class ProductService {
         const toAdd = translationEntities.filter(not(foundIn(existingTranslations, 'languageCode')));
         const toUpdate = translationEntities.filter(foundIn(existingTranslations, 'languageCode'));
 
-        return this.connection
+        await this.connection
             .getCustomRepository(ProductRepository)
-            .update(updateProductDto, toUpdate, toAdd, toDelete)
-            .then(createdProduct => translateDeep(createdProduct));
+            .update(updateProductDto, toUpdate, toAdd, toDelete);
+
+        return this.findOne(updateProductDto.id, DEFAULT_LANGUAGE_CODE);
     }
 
     private translationInputsToEntities(
@@ -88,8 +95,4 @@ export class ProductService {
             return entity;
         });
     }
-
-    private translateProductEntity(product: Product): Product {
-        return translateDeep(product, ['optionGroups', 'variants', ['variants', 'options']]);
-    }
 }