You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

663 lines
14KB

  1. /*
  2. * Copyright (c) 2018 DeineAgentur UG https://www.deineagentur.com. All rights reserved.
  3. * Licensed under the MIT License. See LICENSE file in the project root for full license information.
  4. */
  5. package gotext
  6. import (
  7. "os"
  8. "path"
  9. "testing"
  10. )
  11. func TestPo_Get(t *testing.T) {
  12. // Create po object
  13. po := new(Po)
  14. // Try to parse a directory
  15. po.ParseFile(path.Clean(os.TempDir()))
  16. // Parse file
  17. po.ParseFile("fixtures/en_US/default.po")
  18. // Test translations
  19. tr := po.Get("My text")
  20. if tr != "Translated text" {
  21. t.Errorf("Expected 'Translated text' but got '%s'", tr)
  22. }
  23. // Test translations
  24. tr = po.Get("language")
  25. if tr != "en_US" {
  26. t.Errorf("Expected 'en_US' but got '%s'", tr)
  27. }
  28. }
  29. func TestPo(t *testing.T) {
  30. // Set PO content
  31. str := `
  32. msgid ""
  33. msgstr ""
  34. # Initial comment
  35. # Headers below
  36. "Language: en\n"
  37. "Content-Type: text/plain; charset=UTF-8\n"
  38. "Content-Transfer-Encoding: 8bit\n"
  39. "Plural-Forms: nplurals=2; plural=(n != 1);\n"
  40. # Some comment
  41. msgid "My text"
  42. msgstr "Translated text"
  43. # More comments
  44. msgid "Another string"
  45. msgstr ""
  46. # Multi-line msgid
  47. msgid ""
  48. "multi"
  49. "line"
  50. "id"
  51. msgstr "id with multiline content"
  52. # Multi-line msgid_plural
  53. msgid ""
  54. "multi"
  55. "line"
  56. "plural"
  57. "id"
  58. msgstr "plural id with multiline content"
  59. #Multi-line string
  60. msgid "Multi-line"
  61. msgstr ""
  62. "Multi "
  63. "line"
  64. msgid "One with var: %s"
  65. msgid_plural "Several with vars: %s"
  66. msgstr[0] "This one is the singular: %s"
  67. msgstr[1] "This one is the plural: %s"
  68. msgstr[2] "And this is the second plural form: %s"
  69. msgctxt "Ctx"
  70. msgid "One with var: %s"
  71. msgid_plural "Several with vars: %s"
  72. msgstr[0] "This one is the singular in a Ctx context: %s"
  73. msgstr[1] "This one is the plural in a Ctx context: %s"
  74. msgid "Some random"
  75. msgstr "Some random Translation"
  76. msgctxt "Ctx"
  77. msgid "Some random in a context"
  78. msgstr "Some random Translation in a context"
  79. msgid "Empty Translation"
  80. msgstr ""
  81. msgid "Empty plural form singular"
  82. msgid_plural "Empty plural form"
  83. msgstr[0] "Singular translated"
  84. msgstr[1] ""
  85. msgid "More"
  86. msgstr "More Translation"
  87. `
  88. // Write PO content to file
  89. filename := path.Clean(os.TempDir() + string(os.PathSeparator) + "default.po")
  90. f, err := os.Create(filename)
  91. if err != nil {
  92. t.Fatalf("Can't create test file: %s", err.Error())
  93. }
  94. defer f.Close()
  95. _, err = f.WriteString(str)
  96. if err != nil {
  97. t.Fatalf("Can't write to test file: %s", err.Error())
  98. }
  99. // Create po object
  100. po := new(Po)
  101. // Try to parse a directory
  102. po.ParseFile(path.Clean(os.TempDir()))
  103. // Parse file
  104. po.ParseFile(filename)
  105. // Test translations
  106. tr := po.Get("My text")
  107. if tr != "Translated text" {
  108. t.Errorf("Expected 'Translated text' but got '%s'", tr)
  109. }
  110. v := "Variable"
  111. tr = po.Get("One with var: %s", v)
  112. if tr != "This one is the singular: Variable" {
  113. t.Errorf("Expected 'This one is the singular: Variable' but got '%s'", tr)
  114. }
  115. // Test multi-line id
  116. tr = po.Get("multilineid")
  117. if tr != "id with multiline content" {
  118. t.Errorf("Expected 'id with multiline content' but got '%s'", tr)
  119. }
  120. // Test multi-line plural id
  121. tr = po.Get("multilinepluralid")
  122. if tr != "plural id with multiline content" {
  123. t.Errorf("Expected 'plural id with multiline content' but got '%s'", tr)
  124. }
  125. // Test multi-line
  126. tr = po.Get("Multi-line")
  127. if tr != "Multi line" {
  128. t.Errorf("Expected 'Multi line' but got '%s'", tr)
  129. }
  130. // Test plural
  131. tr = po.GetN("One with var: %s", "Several with vars: %s", 2, v)
  132. if tr != "This one is the plural: Variable" {
  133. t.Errorf("Expected 'This one is the plural: Variable' but got '%s'", tr)
  134. }
  135. // Test not existent translations
  136. tr = po.Get("This is a test")
  137. if tr != "This is a test" {
  138. t.Errorf("Expected 'This is a test' but got '%s'", tr)
  139. }
  140. tr = po.GetN("This is a test", "This are tests", 100)
  141. if tr != "This are tests" {
  142. t.Errorf("Expected 'This are tests' but got '%s'", tr)
  143. }
  144. // Test translations with existence check
  145. tr, exists := po.GetE("My text")
  146. if (tr != "Translated text") || (!exists) {
  147. t.Errorf("Expected 'Translated text', true but got '%s', %v", tr, exists)
  148. }
  149. tr, exists = po.GetE("I don't exist")
  150. if exists {
  151. t.Errorf("Expected 'I don't exist' not to exist but got '%s'", tr)
  152. }
  153. tr = po.GetN("I don't exist", "We don't exist", 100)
  154. if exists {
  155. t.Errorf("Expected 'I/We don't exist' not to exist but got '%s'", tr)
  156. }
  157. // Test context translations
  158. v = "Test"
  159. tr = po.GetC("One with var: %s", "Ctx", v)
  160. if tr != "This one is the singular in a Ctx context: Test" {
  161. t.Errorf("Expected 'This one is the singular in a Ctx context: Test' but got '%s'", tr)
  162. }
  163. // Test plural
  164. tr = po.GetNC("One with var: %s", "Several with vars: %s", 17, "Ctx", v)
  165. if tr != "This one is the plural in a Ctx context: Test" {
  166. t.Errorf("Expected 'This one is the plural in a Ctx context: Test' but got '%s'", tr)
  167. }
  168. // Test default plural vs singular return responses
  169. tr = po.GetN("Original", "Original plural", 4)
  170. if tr != "Original plural" {
  171. t.Errorf("Expected 'Original plural' but got '%s'", tr)
  172. }
  173. tr = po.GetN("Original", "Original plural", 1)
  174. if tr != "Original" {
  175. t.Errorf("Expected 'Original' but got '%s'", tr)
  176. }
  177. // Test empty Translation strings
  178. tr = po.Get("Empty Translation")
  179. if tr != "Empty Translation" {
  180. t.Errorf("Expected 'Empty Translation' but got '%s'", tr)
  181. }
  182. tr = po.Get("Empty plural form singular")
  183. if tr != "Singular translated" {
  184. t.Errorf("Expected 'Singular translated' but got '%s'", tr)
  185. }
  186. tr = po.GetN("Empty plural form singular", "Empty plural form", 1)
  187. if tr != "Singular translated" {
  188. t.Errorf("Expected 'Singular translated' but got '%s'", tr)
  189. }
  190. tr = po.GetN("Empty plural form singular", "Empty plural form", 2)
  191. if tr != "Empty plural form" {
  192. t.Errorf("Expected 'Empty plural form' but got '%s'", tr)
  193. }
  194. // Test last Translation
  195. tr = po.Get("More")
  196. if tr != "More Translation" {
  197. t.Errorf("Expected 'More Translation' but got '%s'", tr)
  198. }
  199. }
  200. func TestPlural(t *testing.T) {
  201. // Set PO content
  202. str := `
  203. msgid ""
  204. msgstr ""
  205. "Plural-Forms: nplurals=2; plural=(n != 1);\n"
  206. msgid "Singular: %s"
  207. msgid_plural "Plural: %s"
  208. msgstr[0] "TR Singular: %s"
  209. msgstr[1] "TR Plural: %s"
  210. msgstr[2] "TR Plural 2: %s"
  211. `
  212. // Create po object
  213. po := new(Po)
  214. po.Parse([]byte(str))
  215. v := "Var"
  216. tr := po.GetN("Singular: %s", "Plural: %s", 2, v)
  217. if tr != "TR Plural: Var" {
  218. t.Errorf("Expected 'TR Plural: Var' but got '%s'", tr)
  219. }
  220. tr = po.GetN("Singular: %s", "Plural: %s", 1, v)
  221. if tr != "TR Singular: Var" {
  222. t.Errorf("Expected 'TR Singular: Var' but got '%s'", tr)
  223. }
  224. }
  225. func TestPluralNoHeaderInformation(t *testing.T) {
  226. // Set PO content
  227. str := `
  228. msgid ""
  229. msgstr ""
  230. msgid "Singular: %s"
  231. msgid_plural "Plural: %s"
  232. msgstr[0] "TR Singular: %s"
  233. msgstr[1] "TR Plural: %s"
  234. msgstr[2] "TR Plural 2: %s"
  235. `
  236. // Create po object
  237. po := new(Po)
  238. po.Parse([]byte(str))
  239. v := "Var"
  240. tr := po.GetN("Singular: %s", "Plural: %s", 2, v)
  241. if tr != "TR Plural: Var" {
  242. t.Errorf("Expected 'TR Plural: Var' but got '%s'", tr)
  243. }
  244. tr = po.GetN("Singular: %s", "Plural: %s", 1, v)
  245. if tr != "TR Singular: Var" {
  246. t.Errorf("Expected 'TR Singular: Var' but got '%s'", tr)
  247. }
  248. }
  249. func TestPoHeaders(t *testing.T) {
  250. // Set PO content
  251. str := `
  252. msgid ""
  253. msgstr ""
  254. # Initial comment
  255. # Headers below
  256. "Language: en\n"
  257. "Content-Type: text/plain; charset=UTF-8\n"
  258. "Content-Transfer-Encoding: 8bit\n"
  259. "Plural-Forms: nplurals=2; plural=(n != 1);\n"
  260. # Some comment
  261. msgid "Example"
  262. msgstr "Translated example"
  263. `
  264. // Create po object
  265. po := new(Po)
  266. // Parse
  267. po.Parse([]byte(str))
  268. // Check headers expected
  269. if po.Language != "en" {
  270. t.Errorf("Expected 'Language: en' but got '%s'", po.Language)
  271. }
  272. // Check headers expected
  273. if po.PluralForms != "nplurals=2; plural=(n != 1);" {
  274. t.Errorf("Expected 'Plural-Forms: nplurals=2; plural=(n != 1);' but got '%s'", po.PluralForms)
  275. }
  276. }
  277. func TestMissingPoHeadersSupport(t *testing.T) {
  278. // Set PO content
  279. str := `
  280. msgid "Example"
  281. msgstr "Translated example"
  282. `
  283. // Create po object
  284. po := new(Po)
  285. // Parse
  286. po.Parse([]byte(str))
  287. // Check Translation expected
  288. if po.Get("Example") != "Translated example" {
  289. t.Errorf("Expected 'Translated example' but got '%s'", po.Get("Example"))
  290. }
  291. }
  292. func TestPluralFormsSingle(t *testing.T) {
  293. // Single form
  294. str := `
  295. msgid ""
  296. msgstr ""
  297. "Plural-Forms: nplurals=1; plural=0;"
  298. # Some comment
  299. msgid "Singular"
  300. msgid_plural "Plural"
  301. msgstr[0] "Singular form"
  302. msgstr[1] "Plural form 1"
  303. msgstr[2] "Plural form 2"
  304. msgstr[3] "Plural form 3"
  305. `
  306. // Create po object
  307. po := new(Po)
  308. // Parse
  309. po.Parse([]byte(str))
  310. // Check plural form
  311. n := po.pluralForm(0)
  312. if n != 0 {
  313. t.Errorf("Expected 0 for pluralForm(0), got %d", n)
  314. }
  315. n = po.pluralForm(1)
  316. if n != 0 {
  317. t.Errorf("Expected 0 for pluralForm(1), got %d", n)
  318. }
  319. n = po.pluralForm(2)
  320. if n != 0 {
  321. t.Errorf("Expected 0 for pluralForm(2), got %d", n)
  322. }
  323. n = po.pluralForm(3)
  324. if n != 0 {
  325. t.Errorf("Expected 0 for pluralForm(3), got %d", n)
  326. }
  327. n = po.pluralForm(50)
  328. if n != 0 {
  329. t.Errorf("Expected 0 for pluralForm(50), got %d", n)
  330. }
  331. }
  332. func TestPluralForms2(t *testing.T) {
  333. // 2 forms
  334. str := `
  335. msgid ""
  336. msgstr ""
  337. "Plural-Forms: nplurals=2; plural=n != 1;"
  338. # Some comment
  339. msgid "Singular"
  340. msgid_plural "Plural"
  341. msgstr[0] "Singular form"
  342. msgstr[1] "Plural form 1"
  343. msgstr[2] "Plural form 2"
  344. msgstr[3] "Plural form 3"
  345. `
  346. // Create po object
  347. po := new(Po)
  348. // Parse
  349. po.Parse([]byte(str))
  350. // Check plural form
  351. n := po.pluralForm(0)
  352. if n != 1 {
  353. t.Errorf("Expected 1 for pluralForm(0), got %d", n)
  354. }
  355. n = po.pluralForm(1)
  356. if n != 0 {
  357. t.Errorf("Expected 0 for pluralForm(1), got %d", n)
  358. }
  359. n = po.pluralForm(2)
  360. if n != 1 {
  361. t.Errorf("Expected 1 for pluralForm(2), got %d", n)
  362. }
  363. n = po.pluralForm(3)
  364. if n != 1 {
  365. t.Errorf("Expected 1 for pluralForm(3), got %d", n)
  366. }
  367. }
  368. func TestPluralForms3(t *testing.T) {
  369. // 3 forms
  370. str := `
  371. msgid ""
  372. msgstr ""
  373. "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;"
  374. # Some comment
  375. msgid "Singular"
  376. msgid_plural "Plural"
  377. msgstr[0] "Singular form"
  378. msgstr[1] "Plural form 1"
  379. msgstr[2] "Plural form 2"
  380. msgstr[3] "Plural form 3"
  381. `
  382. // Create po object
  383. po := new(Po)
  384. // Parse
  385. po.Parse([]byte(str))
  386. // Check plural form
  387. n := po.pluralForm(0)
  388. if n != 2 {
  389. t.Errorf("Expected 2 for pluralForm(0), got %d", n)
  390. }
  391. n = po.pluralForm(1)
  392. if n != 0 {
  393. t.Errorf("Expected 0 for pluralForm(1), got %d", n)
  394. }
  395. n = po.pluralForm(2)
  396. if n != 1 {
  397. t.Errorf("Expected 1 for pluralForm(2), got %d", n)
  398. }
  399. n = po.pluralForm(3)
  400. if n != 1 {
  401. t.Errorf("Expected 1 for pluralForm(3), got %d", n)
  402. }
  403. n = po.pluralForm(100)
  404. if n != 1 {
  405. t.Errorf("Expected 1 for pluralForm(100), got %d", n)
  406. }
  407. n = po.pluralForm(49)
  408. if n != 1 {
  409. t.Errorf("Expected 1 for pluralForm(3), got %d", n)
  410. }
  411. }
  412. func TestPluralFormsSpecial(t *testing.T) {
  413. // 3 forms special
  414. str := `
  415. msgid ""
  416. msgstr ""
  417. "Plural-Forms: nplurals=3;"
  418. "plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
  419. # Some comment
  420. msgid "Singular"
  421. msgid_plural "Plural"
  422. msgstr[0] "Singular form"
  423. msgstr[1] "Plural form 1"
  424. msgstr[2] "Plural form 2"
  425. msgstr[3] "Plural form 3"
  426. `
  427. // Create po object
  428. po := new(Po)
  429. // Parse
  430. po.Parse([]byte(str))
  431. // Check plural form
  432. n := po.pluralForm(1)
  433. if n != 0 {
  434. t.Errorf("Expected 0 for pluralForm(1), got %d", n)
  435. }
  436. n = po.pluralForm(2)
  437. if n != 1 {
  438. t.Errorf("Expected 1 for pluralForm(2), got %d", n)
  439. }
  440. n = po.pluralForm(4)
  441. if n != 1 {
  442. t.Errorf("Expected 4 for pluralForm(4), got %d", n)
  443. }
  444. n = po.pluralForm(0)
  445. if n != 2 {
  446. t.Errorf("Expected 2 for pluralForm(2), got %d", n)
  447. }
  448. n = po.pluralForm(1000)
  449. if n != 2 {
  450. t.Errorf("Expected 2 for pluralForm(1000), got %d", n)
  451. }
  452. }
  453. func TestTranslationObject(t *testing.T) {
  454. tr := NewTranslation()
  455. str := tr.Get()
  456. if str != "" {
  457. t.Errorf("Expected '' but got '%s'", str)
  458. }
  459. // Set id
  460. tr.ID = "Text"
  461. str = tr.Get()
  462. // Get again
  463. if str != "Text" {
  464. t.Errorf("Expected 'Text' but got '%s'", str)
  465. }
  466. }
  467. func TestPoRace(t *testing.T) {
  468. // Set PO content
  469. str := `# Some comment
  470. msgid "My text"
  471. msgstr "Translated text"
  472. # More comments
  473. msgid "Another string"
  474. msgstr ""
  475. msgid "One with var: %s"
  476. msgid_plural "Several with vars: %s"
  477. msgstr[0] "This one is the singular: %s"
  478. msgstr[1] "This one is the plural: %s"
  479. msgstr[2] "And this is the second plural form: %s"
  480. `
  481. // Create Po object
  482. po := new(Po)
  483. // Create sync channels
  484. pc := make(chan bool)
  485. rc := make(chan bool)
  486. // Parse po content in a goroutine
  487. go func(po *Po, done chan bool) {
  488. po.Parse([]byte(str))
  489. done <- true
  490. }(po, pc)
  491. // Read some Translation on a goroutine
  492. go func(po *Po, done chan bool) {
  493. po.Get("My text")
  494. done <- true
  495. }(po, rc)
  496. // Read something at top level
  497. po.Get("My text")
  498. // Wait for goroutines to finish
  499. <-pc
  500. <-rc
  501. }
  502. func TestNewPoTranslatorRace(t *testing.T) {
  503. // Create Po object
  504. mo := NewPoTranslator()
  505. // Create sync channels
  506. pc := make(chan bool)
  507. rc := make(chan bool)
  508. // Parse po content in a goroutine
  509. go func(mo Translator, done chan bool) {
  510. // Parse file
  511. mo.ParseFile("fixtures/en_US/default.po")
  512. done <- true
  513. }(mo, pc)
  514. // Read some Translation on a goroutine
  515. go func(mo Translator, done chan bool) {
  516. mo.Get("My text")
  517. done <- true
  518. }(mo, rc)
  519. // Read something at top level
  520. mo.Get("My text")
  521. // Wait for goroutines to finish
  522. <-pc
  523. <-rc
  524. }
  525. func TestPoBinaryEncoding(t *testing.T) {
  526. // Create po objects
  527. po := new(Po)
  528. po2 := new(Po)
  529. // Parse file
  530. po.ParseFile("fixtures/en_US/default.po")
  531. buff, err := po.MarshalBinary()
  532. if err != nil {
  533. t.Fatal(err)
  534. }
  535. err = po2.UnmarshalBinary(buff)
  536. if err != nil {
  537. t.Fatal(err)
  538. }
  539. // Test translations
  540. tr := po2.Get("My text")
  541. if tr != "Translated text" {
  542. t.Errorf("Expected 'Translated text' but got '%s'", tr)
  543. }
  544. // Test translations
  545. tr = po2.Get("language")
  546. if tr != "en_US" {
  547. t.Errorf("Expected 'en_US' but got '%s'", tr)
  548. }
  549. }