translator_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. package ut
  2. import (
  3. "fmt"
  4. "testing"
  5. "github.com/go-playground/locales"
  6. "github.com/go-playground/locales/en"
  7. "github.com/go-playground/locales/en_CA"
  8. "github.com/go-playground/locales/nl"
  9. )
  10. // NOTES:
  11. // - Run "go test" to run tests
  12. // - Run "gocov test | gocov report" to report on test converage by file
  13. // - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
  14. //
  15. // or
  16. //
  17. // -- may be a good idea to change to output path to somewherelike /tmp
  18. // go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
  19. //
  20. func TestBasicTranslation(t *testing.T) {
  21. e := en.New()
  22. uni := New(e, e)
  23. en, found := uni.GetTranslator("en") // or fallback if fails to find 'en'
  24. if !found {
  25. t.Fatalf("Expected '%t' Got '%t'", true, found)
  26. }
  27. translations := []struct {
  28. key interface{}
  29. trans string
  30. expected error
  31. expectedError bool
  32. override bool
  33. }{
  34. {
  35. key: "test_trans",
  36. trans: "Welcome {0}",
  37. expected: nil,
  38. },
  39. {
  40. key: "test_trans2",
  41. trans: "{0} to the {1}.",
  42. expected: nil,
  43. },
  44. {
  45. key: "test_trans3",
  46. trans: "Welcome {0} to the {1}",
  47. expected: nil,
  48. },
  49. {
  50. key: "test_trans4",
  51. trans: "{0}{1}",
  52. expected: nil,
  53. },
  54. {
  55. key: "test_trans",
  56. trans: "{0}{1}",
  57. expected: &ErrConflictingTranslation{key: "bad_trans", text: "{0}{1}"},
  58. expectedError: true,
  59. },
  60. {
  61. key: "test_trans",
  62. trans: "Welcome {0} to the {1}.",
  63. expected: nil,
  64. override: true,
  65. },
  66. }
  67. for _, tt := range translations {
  68. err := en.Add(tt.key, tt.trans, tt.override)
  69. if err != tt.expected {
  70. if !tt.expectedError && err.Error() != tt.expected.Error() {
  71. t.Errorf("Expected '%s' Got '%s'", tt.expected, err)
  72. }
  73. }
  74. }
  75. tests := []struct {
  76. key interface{}
  77. params []string
  78. expected string
  79. expectedError bool
  80. }{
  81. {
  82. key: "test_trans",
  83. params: []string{"Joeybloggs", "The Test"},
  84. expected: "Welcome Joeybloggs to the The Test.",
  85. },
  86. {
  87. key: "test_trans2",
  88. params: []string{"Joeybloggs", "The Test"},
  89. expected: "Joeybloggs to the The Test.",
  90. },
  91. {
  92. key: "test_trans3",
  93. params: []string{"Joeybloggs", "The Test"},
  94. expected: "Welcome Joeybloggs to the The Test",
  95. },
  96. {
  97. key: "test_trans4",
  98. params: []string{"Joeybloggs", "The Test"},
  99. expected: "JoeybloggsThe Test",
  100. },
  101. // bad translation
  102. {
  103. key: "non-existant-key",
  104. params: []string{"Joeybloggs", "The Test"},
  105. expected: "",
  106. expectedError: true,
  107. },
  108. }
  109. for _, tt := range tests {
  110. s, err := en.T(tt.key, tt.params...)
  111. if s != tt.expected {
  112. if !tt.expectedError && err != ErrUnknowTranslation {
  113. t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
  114. }
  115. }
  116. }
  117. }
  118. func TestCardinalTranslation(t *testing.T) {
  119. e := en.New()
  120. uni := New(e, e)
  121. en, found := uni.GetTranslator("en")
  122. if !found {
  123. t.Fatalf("Expected '%t' Got '%t'", true, found)
  124. }
  125. translations := []struct {
  126. key interface{}
  127. trans string
  128. rule locales.PluralRule
  129. expected error
  130. expectedError bool
  131. override bool
  132. }{
  133. // bad translation
  134. {
  135. key: "cardinal_test",
  136. trans: "You have a day left.",
  137. rule: locales.PluralRuleOne,
  138. expected: &ErrCardinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddCardinal'", paramZero)},
  139. expectedError: true,
  140. },
  141. {
  142. key: "cardinal_test",
  143. trans: "You have {0} day",
  144. rule: locales.PluralRuleOne,
  145. expected: nil,
  146. },
  147. {
  148. key: "cardinal_test",
  149. trans: "You have {0} days left.",
  150. rule: locales.PluralRuleOther,
  151. expected: nil,
  152. },
  153. {
  154. key: "cardinal_test",
  155. trans: "You have {0} days left.",
  156. rule: locales.PluralRuleOther,
  157. expected: &ErrConflictingTranslation{key: "cardinal_test", rule: locales.PluralRuleOther, text: "You have {0} days left."},
  158. expectedError: true,
  159. },
  160. {
  161. key: "cardinal_test",
  162. trans: "You have {0} day left.",
  163. rule: locales.PluralRuleOne,
  164. expected: nil,
  165. override: true,
  166. },
  167. }
  168. for _, tt := range translations {
  169. err := en.AddCardinal(tt.key, tt.trans, tt.rule, tt.override)
  170. if err != tt.expected {
  171. if !tt.expectedError || err.Error() != tt.expected.Error() {
  172. t.Errorf("Expected '<nil>' Got '%s'", err)
  173. }
  174. }
  175. }
  176. tests := []struct {
  177. key interface{}
  178. num float64
  179. digits uint64
  180. param string
  181. expected string
  182. expectedError bool
  183. }{
  184. {
  185. key: "cardinal_test",
  186. num: 1,
  187. digits: 0,
  188. param: string(en.FmtNumber(1, 0)),
  189. expected: "You have 1 day left.",
  190. },
  191. // bad translation key
  192. {
  193. key: "non-existant",
  194. num: 1,
  195. digits: 0,
  196. param: string(en.FmtNumber(1, 0)),
  197. expected: "",
  198. expectedError: true,
  199. },
  200. }
  201. for _, tt := range tests {
  202. s, err := en.C(tt.key, tt.num, tt.digits, tt.param)
  203. if err != nil {
  204. if !tt.expectedError && err != ErrUnknowTranslation {
  205. t.Errorf("Expected '<nil>' Got '%s'", err)
  206. }
  207. }
  208. if s != tt.expected {
  209. t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
  210. }
  211. }
  212. }
  213. func TestOrdinalTranslation(t *testing.T) {
  214. e := en.New()
  215. uni := New(e, e)
  216. en, found := uni.GetTranslator("en")
  217. if !found {
  218. t.Fatalf("Expected '%t' Got '%t'", true, found)
  219. }
  220. translations := []struct {
  221. key interface{}
  222. trans string
  223. rule locales.PluralRule
  224. expected error
  225. expectedError bool
  226. override bool
  227. }{
  228. // bad translation
  229. {
  230. key: "day",
  231. trans: "st",
  232. rule: locales.PluralRuleOne,
  233. expected: &ErrOrdinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddOrdinal'", paramZero)},
  234. expectedError: true,
  235. },
  236. {
  237. key: "day",
  238. trans: "{0}sfefewt",
  239. rule: locales.PluralRuleOne,
  240. expected: nil,
  241. },
  242. {
  243. key: "day",
  244. trans: "{0}nd",
  245. rule: locales.PluralRuleTwo,
  246. expected: nil,
  247. },
  248. {
  249. key: "day",
  250. trans: "{0}rd",
  251. rule: locales.PluralRuleFew,
  252. expected: nil,
  253. },
  254. {
  255. key: "day",
  256. trans: "{0}th",
  257. rule: locales.PluralRuleOther,
  258. expected: nil,
  259. },
  260. // bad translation
  261. {
  262. key: "day",
  263. trans: "{0}th",
  264. rule: locales.PluralRuleOther,
  265. expected: &ErrConflictingTranslation{key: "day", rule: locales.PluralRuleOther, text: "{0}th"},
  266. expectedError: true,
  267. },
  268. {
  269. key: "day",
  270. trans: "{0}st",
  271. rule: locales.PluralRuleOne,
  272. expected: nil,
  273. override: true,
  274. },
  275. }
  276. for _, tt := range translations {
  277. err := en.AddOrdinal(tt.key, tt.trans, tt.rule, tt.override)
  278. if err != tt.expected {
  279. if !tt.expectedError || err.Error() != tt.expected.Error() {
  280. t.Errorf("Expected '<nil>' Got '%s'", err)
  281. }
  282. }
  283. }
  284. tests := []struct {
  285. key interface{}
  286. num float64
  287. digits uint64
  288. param string
  289. expected string
  290. expectedError bool
  291. }{
  292. {
  293. key: "day",
  294. num: 1,
  295. digits: 0,
  296. param: string(en.FmtNumber(1, 0)),
  297. expected: "1st",
  298. },
  299. {
  300. key: "day",
  301. num: 2,
  302. digits: 0,
  303. param: string(en.FmtNumber(2, 0)),
  304. expected: "2nd",
  305. },
  306. {
  307. key: "day",
  308. num: 3,
  309. digits: 0,
  310. param: string(en.FmtNumber(3, 0)),
  311. expected: "3rd",
  312. },
  313. {
  314. key: "day",
  315. num: 4,
  316. digits: 0,
  317. param: string(en.FmtNumber(4, 0)),
  318. expected: "4th",
  319. },
  320. {
  321. key: "day",
  322. num: 10258.43,
  323. digits: 0,
  324. param: string(en.FmtNumber(10258.43, 0)),
  325. expected: "10,258th",
  326. },
  327. // bad translation
  328. {
  329. key: "d-day",
  330. num: 10258.43,
  331. digits: 0,
  332. param: string(en.FmtNumber(10258.43, 0)),
  333. expected: "",
  334. expectedError: true,
  335. },
  336. }
  337. for _, tt := range tests {
  338. s, err := en.O(tt.key, tt.num, tt.digits, tt.param)
  339. if err != nil {
  340. if !tt.expectedError && err != ErrUnknowTranslation {
  341. t.Errorf("Expected '<nil>' Got '%s'", err)
  342. }
  343. }
  344. if s != tt.expected {
  345. t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
  346. }
  347. }
  348. }
  349. func TestRangeTranslation(t *testing.T) {
  350. n := nl.New()
  351. uni := New(n, n)
  352. // dutch
  353. nl, found := uni.GetTranslator("nl")
  354. if !found {
  355. t.Fatalf("Expected '%t' Got '%t'", true, found)
  356. }
  357. translations := []struct {
  358. key interface{}
  359. trans string
  360. rule locales.PluralRule
  361. expected error
  362. expectedError bool
  363. override bool
  364. }{
  365. // bad translation
  366. {
  367. key: "day",
  368. trans: "er -{1} dag vertrokken",
  369. rule: locales.PluralRuleOne,
  370. expected: &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, are you sure you're adding a Range Translation?", paramZero)},
  371. expectedError: true,
  372. },
  373. // bad translation
  374. {
  375. key: "day",
  376. trans: "er {0}- dag vertrokken",
  377. rule: locales.PluralRuleOne,
  378. expected: &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, a Range Translation requires two parameters", paramOne)},
  379. expectedError: true,
  380. },
  381. {
  382. key: "day",
  383. trans: "er {0}-{1} dag",
  384. rule: locales.PluralRuleOne,
  385. expected: nil,
  386. },
  387. {
  388. key: "day",
  389. trans: "er zijn {0}-{1} dagen over",
  390. rule: locales.PluralRuleOther,
  391. expected: nil,
  392. },
  393. // bad translation
  394. {
  395. key: "day",
  396. trans: "er zijn {0}-{1} dagen over",
  397. rule: locales.PluralRuleOther,
  398. expected: &ErrConflictingTranslation{key: "day", rule: locales.PluralRuleOther, text: "er zijn {0}-{1} dagen over"},
  399. expectedError: true,
  400. },
  401. {
  402. key: "day",
  403. trans: "er {0}-{1} dag vertrokken",
  404. rule: locales.PluralRuleOne,
  405. expected: nil,
  406. override: true,
  407. },
  408. }
  409. for _, tt := range translations {
  410. err := nl.AddRange(tt.key, tt.trans, tt.rule, tt.override)
  411. if err != tt.expected {
  412. if !tt.expectedError || err.Error() != tt.expected.Error() {
  413. t.Errorf("Expected '%#v' Got '%s'", tt.expected, err)
  414. }
  415. }
  416. }
  417. tests := []struct {
  418. key interface{}
  419. num1 float64
  420. digits1 uint64
  421. num2 float64
  422. digits2 uint64
  423. param1 string
  424. param2 string
  425. expected string
  426. expectedError bool
  427. }{
  428. {
  429. key: "day",
  430. num1: 1,
  431. digits1: 0,
  432. num2: 2,
  433. digits2: 0,
  434. param1: string(nl.FmtNumber(1, 0)),
  435. param2: string(nl.FmtNumber(2, 0)),
  436. expected: "er zijn 1-2 dagen over",
  437. },
  438. {
  439. key: "day",
  440. num1: 0,
  441. digits1: 0,
  442. num2: 1,
  443. digits2: 0,
  444. param1: string(nl.FmtNumber(0, 0)),
  445. param2: string(nl.FmtNumber(1, 0)),
  446. expected: "er 0-1 dag vertrokken",
  447. },
  448. {
  449. key: "day",
  450. num1: 0,
  451. digits1: 0,
  452. num2: 2,
  453. digits2: 0,
  454. param1: string(nl.FmtNumber(0, 0)),
  455. param2: string(nl.FmtNumber(2, 0)),
  456. expected: "er zijn 0-2 dagen over",
  457. },
  458. // bad translations from here
  459. {
  460. key: "d-day",
  461. num1: 0,
  462. digits1: 0,
  463. num2: 2,
  464. digits2: 0,
  465. param1: string(nl.FmtNumber(0, 0)),
  466. param2: string(nl.FmtNumber(2, 0)),
  467. expected: "",
  468. expectedError: true,
  469. },
  470. }
  471. for _, tt := range tests {
  472. s, err := nl.R(tt.key, tt.num1, tt.digits1, tt.num2, tt.digits2, tt.param1, tt.param2)
  473. if err != nil {
  474. if !tt.expectedError && err != ErrUnknowTranslation {
  475. t.Errorf("Expected '<nil>' Got '%s'", err)
  476. }
  477. }
  478. if s != tt.expected {
  479. t.Errorf("Expected '%s' Got '%s'", tt.expected, s)
  480. }
  481. }
  482. }
  483. func TestFallbackTranslator(t *testing.T) {
  484. e := en.New()
  485. uni := New(e, e)
  486. en, found := uni.GetTranslator("en")
  487. if !found {
  488. t.Fatalf("Expected '%t' Got '%t'", true, found)
  489. }
  490. if en.Locale() != "en" {
  491. t.Errorf("Expected '%s' Got '%s'", "en", en.Locale())
  492. }
  493. fallback, _ := uni.GetTranslator("nl")
  494. if fallback.Locale() != "en" {
  495. t.Errorf("Expected '%s' Got '%s'", "en", fallback.Locale())
  496. }
  497. en, _ = uni.FindTranslator("nl", "en")
  498. if en.Locale() != "en" {
  499. t.Errorf("Expected '%s' Got '%s'", "en", en.Locale())
  500. }
  501. fallback, _ = uni.FindTranslator("nl")
  502. if fallback.Locale() != "en" {
  503. t.Errorf("Expected '%s' Got '%s'", "en", fallback.Locale())
  504. }
  505. }
  506. func TestAddTranslator(t *testing.T) {
  507. e := en.New()
  508. n := nl.New()
  509. uni := New(e, n)
  510. tests := []struct {
  511. trans locales.Translator
  512. expected error
  513. expectedError bool
  514. override bool
  515. }{
  516. {
  517. trans: en_CA.New(),
  518. expected: nil,
  519. override: false,
  520. },
  521. {
  522. trans: n,
  523. expected: &ErrExistingTranslator{locale: n.Locale()},
  524. expectedError: true,
  525. override: false,
  526. },
  527. {
  528. trans: e,
  529. expected: &ErrExistingTranslator{locale: e.Locale()},
  530. expectedError: true,
  531. override: false,
  532. },
  533. {
  534. trans: e,
  535. expected: nil,
  536. override: true,
  537. },
  538. }
  539. for _, tt := range tests {
  540. err := uni.AddTranslator(tt.trans, tt.override)
  541. if err != tt.expected {
  542. if !tt.expectedError || err.Error() != tt.expected.Error() {
  543. t.Errorf("Expected '%s' Got '%s'", tt.expected, err)
  544. }
  545. }
  546. }
  547. }
  548. func TestVerifyTranslations(t *testing.T) {
  549. n := nl.New()
  550. // dutch
  551. uni := New(n, n)
  552. loc, _ := uni.GetTranslator("nl")
  553. if loc.Locale() != "nl" {
  554. t.Errorf("Expected '%s' Got '%s'", "nl", loc.Locale())
  555. }
  556. // cardinal checks
  557. err := loc.AddCardinal("day", "je {0} dag hebben verlaten", locales.PluralRuleOne, false)
  558. if err != nil {
  559. t.Fatalf("Expected '<nil>' Got '%s'", err)
  560. }
  561. // fail cardinal rules
  562. expected := &ErrMissingPluralTranslation{translationType: "plural", rule: locales.PluralRuleOther, key: "day"}
  563. err = loc.VerifyTranslations()
  564. if err == nil || err.Error() != expected.Error() {
  565. t.Errorf("Expected '%s' Got '%s'", expected, err)
  566. }
  567. // success cardinal
  568. err = loc.AddCardinal("day", "je {0} dagen hebben verlaten", locales.PluralRuleOther, false)
  569. if err != nil {
  570. t.Fatalf("Expected '<nil>' Got '%s'", err)
  571. }
  572. err = loc.VerifyTranslations()
  573. if err != nil {
  574. t.Fatalf("Expected '<nil>' Got '%s'", err)
  575. }
  576. // range checks
  577. err = loc.AddRange("day", "je {0}-{1} dagen hebben verlaten", locales.PluralRuleOther, false)
  578. if err != nil {
  579. t.Fatalf("Expected '<nil>' Got '%s'", err)
  580. }
  581. // fail range rules
  582. expected = &ErrMissingPluralTranslation{translationType: "range", rule: locales.PluralRuleOne, key: "day"}
  583. err = loc.VerifyTranslations()
  584. if err == nil || err.Error() != expected.Error() {
  585. t.Errorf("Expected '%s' Got '%s'", expected, err)
  586. }
  587. // success range
  588. err = loc.AddRange("day", "je {0}-{1} dag hebben verlaten", locales.PluralRuleOne, false)
  589. if err != nil {
  590. t.Fatalf("Expected '<nil>' Got '%s'", err)
  591. }
  592. err = loc.VerifyTranslations()
  593. if err != nil {
  594. t.Fatalf("Expected '<nil>' Got '%s'", err)
  595. }
  596. // ok so 'nl' aka dutch, ony has one plural rule for ordinals, so going to switch to english from here which has 4
  597. err = uni.AddTranslator(en.New(), false)
  598. if err != nil {
  599. t.Fatalf("Expected '<nil>' Got '%s'", err)
  600. }
  601. loc, _ = uni.GetTranslator("en")
  602. if loc.Locale() != "en" {
  603. t.Errorf("Expected '%s' Got '%s'", "en", loc.Locale())
  604. }
  605. // ordinal checks
  606. err = loc.AddOrdinal("day", "{0}st", locales.PluralRuleOne, false)
  607. if err != nil {
  608. t.Fatalf("Expected '<nil>' Got '%s'", err)
  609. }
  610. err = loc.AddOrdinal("day", "{0}rd", locales.PluralRuleFew, false)
  611. if err != nil {
  612. t.Fatalf("Expected '<nil>' Got '%s'", err)
  613. }
  614. err = loc.AddOrdinal("day", "{0}th", locales.PluralRuleOther, false)
  615. if err != nil {
  616. t.Fatalf("Expected '<nil>' Got '%s'", err)
  617. }
  618. // fail ordinal rules
  619. expected = &ErrMissingPluralTranslation{translationType: "ordinal", rule: locales.PluralRuleTwo, key: "day"}
  620. err = loc.VerifyTranslations()
  621. if err == nil || err.Error() != expected.Error() {
  622. t.Errorf("Expected '%s' Got '%s'", expected, err)
  623. }
  624. // success ordinal
  625. err = loc.AddOrdinal("day", "{0}nd", locales.PluralRuleTwo, false)
  626. if err != nil {
  627. t.Fatalf("Expected '<nil>' Got '%s'", err)
  628. }
  629. err = loc.VerifyTranslations()
  630. if err != nil {
  631. t.Fatalf("Expected '<nil>' Got '%s'", err)
  632. }
  633. }
  634. func TestGetFallback(t *testing.T) {
  635. // dutch
  636. n := nl.New()
  637. e := en.New()
  638. uni := New(e, n)
  639. trans := uni.GetFallback()
  640. expected := "en"
  641. if trans.Locale() != expected {
  642. t.Errorf("Expected '%s' Got '%s'", expected, trans.Locale())
  643. }
  644. }