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.

604 lines
16KB

  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/filepath"
  9. "testing"
  10. )
  11. func TestLocale(t *testing.T) {
  12. // Set PO content
  13. str := `
  14. msgid ""
  15. msgstr ""
  16. # Initial comment
  17. # Headers below
  18. "Language: en\n"
  19. "Content-Type: text/plain; charset=UTF-8\n"
  20. "Content-Transfer-Encoding: 8bit\n"
  21. "Plural-Forms: nplurals=2; plural=(n != 1);\n"
  22. # Some comment
  23. msgid "My text"
  24. msgstr "Translated text"
  25. # More comments
  26. msgid "Another string"
  27. msgstr ""
  28. msgid "One with var: %s"
  29. msgid_plural "Several with vars: %s"
  30. msgstr[0] "This one is the singular: %s"
  31. msgstr[1] "This one is the plural: %s"
  32. msgstr[2] "And this is the second plural form: %s"
  33. msgid "This one has invalid syntax translations"
  34. msgid_plural "Plural index"
  35. msgstr[abc] "Wrong index"
  36. msgstr[1 "Forgot to close brackets"
  37. msgstr[0] "Badly formatted string'
  38. msgctxt "Ctx"
  39. msgid "One with var: %s"
  40. msgid_plural "Several with vars: %s"
  41. msgstr[0] "This one is the singular in a Ctx context: %s"
  42. msgstr[1] "This one is the plural in a Ctx context: %s"
  43. msgid "Some random"
  44. msgstr "Some random Translation"
  45. msgctxt "Ctx"
  46. msgid "Some random in a context"
  47. msgstr "Some random Translation in a context"
  48. msgid "More"
  49. msgstr "More Translation"
  50. `
  51. // Create Locales directory with simplified language code
  52. dirname := filepath.Join("/tmp", "en", "LC_MESSAGES")
  53. err := os.MkdirAll(dirname, os.ModePerm)
  54. if err != nil {
  55. t.Fatalf("Can't create test directory: %s", err.Error())
  56. }
  57. // Write PO content to file
  58. filename := filepath.Join(dirname, "my_domain.po")
  59. f, err := os.Create(filename)
  60. if err != nil {
  61. t.Fatalf("Can't create test file: %s", err.Error())
  62. }
  63. defer f.Close()
  64. _, err = f.WriteString(str)
  65. if err != nil {
  66. t.Fatalf("Can't write to test file: %s", err.Error())
  67. }
  68. // Create Locale with full language code
  69. l := NewLocale("/tmp", "en_US")
  70. // Force nil domain storage
  71. l.Domains = nil
  72. // Add domain
  73. l.AddDomain("my_domain")
  74. // Test translations
  75. tr := l.GetD("my_domain", "My text")
  76. if tr != "Translated text" {
  77. t.Errorf("Expected 'Translated text' but got '%s'", tr)
  78. }
  79. v := "Variable"
  80. tr = l.GetD("my_domain", "One with var: %s", v)
  81. if tr != "This one is the singular: Variable" {
  82. t.Errorf("Expected 'This one is the singular: Variable' but got '%s'", tr)
  83. }
  84. // Test plural
  85. tr = l.GetND("my_domain", "One with var: %s", "Several with vars: %s", 7, v)
  86. if tr != "This one is the plural: Variable" {
  87. t.Errorf("Expected 'This one is the plural: Variable' but got '%s'", tr)
  88. }
  89. // Test context translations
  90. tr = l.GetC("Some random in a context", "Ctx")
  91. if tr != "Some random Translation in a context" {
  92. t.Errorf("Expected 'Some random Translation in a context'. Got '%s'", tr)
  93. }
  94. v = "Test"
  95. tr = l.GetNC("One with var: %s", "Several with vars: %s", 23, "Ctx", v)
  96. if tr != "This one is the plural in a Ctx context: Test" {
  97. t.Errorf("Expected 'This one is the plural in a Ctx context: Test'. Got '%s'", tr)
  98. }
  99. tr = l.GetDC("my_domain", "One with var: %s", "Ctx", v)
  100. if tr != "This one is the singular in a Ctx context: Test" {
  101. t.Errorf("Expected 'This one is the singular in a Ctx context: Test' but got '%s'", tr)
  102. }
  103. // Test plural
  104. tr = l.GetNDC("my_domain", "One with var: %s", "Several with vars: %s", 3, "Ctx", v)
  105. if tr != "This one is the plural in a Ctx context: Test" {
  106. t.Errorf("Expected 'This one is the plural in a Ctx context: Test' but got '%s'", tr)
  107. }
  108. // Test last Translation
  109. tr = l.GetD("my_domain", "More")
  110. if tr != "More Translation" {
  111. t.Errorf("Expected 'More Translation' but got '%s'", tr)
  112. }
  113. }
  114. func TestLocaleFails(t *testing.T) {
  115. // Set PO content
  116. str := `
  117. msgid ""
  118. msgstr ""
  119. # Initial comment
  120. # Headers below
  121. "Language: en\n"
  122. "Content-Type: text/plain; charset=UTF-8\n"
  123. "Content-Transfer-Encoding: 8bit\n"
  124. "Plural-Forms: nplurals=2; plural=(n != 1);\n"
  125. # Some comment
  126. msgid "My text"
  127. msgstr "Translated text"
  128. # More comments
  129. msgid "Another string"
  130. msgstr ""
  131. msgid "One with var: %s"
  132. msgid_plural "Several with vars: %s"
  133. msgstr[0] "This one is the singular: %s"
  134. msgstr[1] "This one is the plural: %s"
  135. msgstr[2] "And this is the second plural form: %s"
  136. msgid "This one has invalid syntax translations"
  137. msgid_plural "Plural index"
  138. msgstr[abc] "Wrong index"
  139. msgstr[1 "Forgot to close brackets"
  140. msgstr[0] "Badly formatted string'
  141. msgid "Invalid formatted id[] with no translations
  142. msgctxt "Ctx"
  143. msgid "One with var: %s"
  144. msgid_plural "Several with vars: %s"
  145. msgstr[0] "This one is the singular in a Ctx context: %s"
  146. msgstr[1] "This one is the plural in a Ctx context: %s"
  147. msgid "Some random"
  148. msgstr "Some random Translation"
  149. msgctxt "Ctx"
  150. msgid "Some random in a context"
  151. msgstr "Some random Translation in a context"
  152. msgid "More"
  153. msgstr "More Translation"
  154. `
  155. // Create Locales directory with simplified language code
  156. dirname := filepath.Join("/tmp", "en", "LC_MESSAGES")
  157. err := os.MkdirAll(dirname, os.ModePerm)
  158. if err != nil {
  159. t.Fatalf("Can't create test directory: %s", err.Error())
  160. }
  161. // Write PO content to file
  162. filename := filepath.Join(dirname, "my_domain.po")
  163. f, err := os.Create(filename)
  164. if err != nil {
  165. t.Fatalf("Can't create test file: %s", err.Error())
  166. }
  167. defer f.Close()
  168. _, err = f.WriteString(str)
  169. if err != nil {
  170. t.Fatalf("Can't write to test file: %s", err.Error())
  171. }
  172. // Create Locale with full language code
  173. l := NewLocale("/tmp", "en_US")
  174. // Force nil domain storage
  175. l.Domains = nil
  176. // Add domain
  177. l.AddDomain("my_domain")
  178. // Test non-existent "default" domain responses
  179. tr := l.GetDomain()
  180. if tr != "my_domain" {
  181. t.Errorf("Expected 'my_domain' but got '%s'", tr)
  182. }
  183. // Set default domain to make it fail
  184. l.SetDomain("default")
  185. // Test non-existent "default" domain responses
  186. tr = l.GetDomain()
  187. if tr != "default" {
  188. t.Errorf("Expected 'default' but got '%s'", tr)
  189. }
  190. // Test non-existent "default" domain responses
  191. tr = l.Get("My text")
  192. if tr != "My text" {
  193. t.Errorf("Expected 'My text' but got '%s'", tr)
  194. }
  195. v := "Variable"
  196. tr = l.GetN("One with var: %s", "Several with vars: %s", 2, v)
  197. if tr != "Several with vars: Variable" {
  198. t.Errorf("Expected 'Several with vars: Variable' but got '%s'", tr)
  199. }
  200. // Test inexistent translations
  201. tr = l.Get("This is a test")
  202. if tr != "This is a test" {
  203. t.Errorf("Expected 'This is a test' but got '%s'", tr)
  204. }
  205. tr = l.GetN("This is a test", "This are tests", 1)
  206. if tr != "This is a test" {
  207. t.Errorf("Expected 'This is a test' but got '%s'", tr)
  208. }
  209. tr = l.GetN("This is a test", "This are tests", 7)
  210. if tr != "This are tests" {
  211. t.Errorf("Expected 'This are tests' but got '%s'", tr)
  212. }
  213. // Test syntax error parsed translations
  214. tr = l.Get("This one has invalid syntax translations")
  215. if tr != "This one has invalid syntax translations" {
  216. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  217. }
  218. tr = l.GetN("This one has invalid syntax translations", "This are tests", 1)
  219. if tr != "This one has invalid syntax translations" {
  220. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  221. }
  222. tr = l.GetN("This one has invalid syntax translations", "This are tests", 2)
  223. if tr != "This are tests" {
  224. t.Errorf("Expected 'This are tests' but got '%s'", tr)
  225. }
  226. // Create Locale with full language code
  227. l = NewLocale("/tmp", "golem")
  228. // Force nil domain storage
  229. l.Domains = nil
  230. // Add domain
  231. l.SetDomain("my_domain")
  232. // Test non-existent "default" domain responses
  233. tr = l.GetDomain()
  234. if tr != "my_domain" {
  235. t.Errorf("Expected 'my_domain' but got '%s'", tr)
  236. }
  237. // Test syntax error parsed translations
  238. tr = l.Get("This one has invalid syntax translations")
  239. if tr != "This one has invalid syntax translations" {
  240. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  241. }
  242. tr = l.GetN("This one has invalid syntax translations", "This are tests", 1)
  243. if tr != "This one has invalid syntax translations" {
  244. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  245. }
  246. tr = l.GetN("This one has invalid syntax translations", "This are tests", 111)
  247. if tr != "This are tests" {
  248. t.Errorf("Expected 'This are tests' but got '%s'", tr)
  249. }
  250. // Create Locale with full language code
  251. l = NewLocale("fixtures/", "fr_FR")
  252. // Force nil domain storage
  253. l.Domains = nil
  254. // Add domain
  255. l.SetDomain("default")
  256. // Test non-existent "default" domain responses
  257. tr = l.GetDomain()
  258. if tr != "default" {
  259. t.Errorf("Expected 'my_domain' but got '%s'", tr)
  260. }
  261. // Test syntax error parsed translations
  262. tr = l.Get("This one has invalid syntax translations")
  263. if tr != "This one has invalid syntax translations" {
  264. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  265. }
  266. tr = l.GetN("This one has invalid syntax translations", "This are tests", 1)
  267. if tr != "This one has invalid syntax translations" {
  268. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  269. }
  270. tr = l.GetN("This one has invalid syntax translations", "This are tests", 21)
  271. if tr != "This are tests" {
  272. t.Errorf("Expected 'This are tests' but got '%s'", tr)
  273. }
  274. // Create Locale with full language code
  275. l = NewLocale("fixtures/", "de_DE")
  276. // Force nil domain storage
  277. l.Domains = nil
  278. // Add domain
  279. l.SetDomain("default")
  280. // Test non-existent "default" domain responses
  281. tr = l.GetDomain()
  282. if tr != "default" {
  283. t.Errorf("Expected 'my_domain' but got '%s'", tr)
  284. }
  285. // Test syntax error parsed translations
  286. tr = l.Get("This one has invalid syntax translations")
  287. if tr != "This one has invalid syntax translations" {
  288. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  289. }
  290. tr = l.GetN("This one has invalid syntax translations", "This are tests", 1)
  291. if tr != "This one has invalid syntax translations" {
  292. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  293. }
  294. tr = l.GetN("This one has invalid syntax translations", "This are tests", 2)
  295. if tr != "This are tests" {
  296. t.Errorf("Expected 'This are tests' but got '%s'", tr)
  297. }
  298. // Create Locale with full language code
  299. l = NewLocale("fixtures/", "de_AT")
  300. // Force nil domain storage
  301. l.Domains = nil
  302. // Add domain
  303. l.SetDomain("default")
  304. // Test non-existent "default" domain responses
  305. tr = l.GetDomain()
  306. if tr != "default" {
  307. t.Errorf("Expected 'my_domain' but got '%s'", tr)
  308. }
  309. // Test syntax error parsed translations
  310. tr = l.Get("This one has invalid syntax translations")
  311. if tr != "This one has invalid syntax translations" {
  312. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  313. }
  314. // Test syntax error parsed translations
  315. tr = l.GetNDC("mega", "This one has invalid syntax translations", "plural", 2, "ctx")
  316. if tr != "plural" {
  317. t.Errorf("Expected 'plural' but got '%s'", tr)
  318. }
  319. tr = l.GetN("This one has invalid syntax translations", "This are tests", 1)
  320. if tr != "This one has invalid syntax translations" {
  321. t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
  322. }
  323. tr = l.GetN("This one has invalid syntax translations", "This are tests", 14)
  324. if tr != "This are tests" {
  325. t.Errorf("Expected 'This are tests' but got '%s'", tr)
  326. }
  327. }
  328. func TestLocaleRace(t *testing.T) {
  329. // Set PO content
  330. str := `# Some comment
  331. msgid "My text"
  332. msgstr "Translated text"
  333. # More comments
  334. msgid "Another string"
  335. msgstr ""
  336. msgid "One with var: %s"
  337. msgid_plural "Several with vars: %s"
  338. msgstr[0] "This one is the singular: %s"
  339. msgstr[1] "This one is the plural: %s"
  340. msgstr[2] "And this is the second plural form: %s"
  341. `
  342. // Create Locales directory with simplified language code
  343. dirname := filepath.Join("/tmp", "es")
  344. err := os.MkdirAll(dirname, os.ModePerm)
  345. if err != nil {
  346. t.Fatalf("Can't create test directory: %s", err.Error())
  347. }
  348. // Write PO content to file
  349. filename := filepath.Join(dirname, "race.po")
  350. f, err := os.Create(filename)
  351. if err != nil {
  352. t.Fatalf("Can't create test file: %s", err.Error())
  353. }
  354. defer f.Close()
  355. _, err = f.WriteString(str)
  356. if err != nil {
  357. t.Fatalf("Can't write to test file: %s", err.Error())
  358. }
  359. // Create Locale
  360. l := NewLocale("/tmp", "es")
  361. // Init sync channels
  362. ac := make(chan bool)
  363. rc := make(chan bool)
  364. // Add domain in goroutine
  365. go func(l *Locale, done chan bool) {
  366. l.AddDomain("race")
  367. done <- true
  368. }(l, ac)
  369. // Get translations in goroutine
  370. go func(l *Locale, done chan bool) {
  371. l.GetD("race", "My text")
  372. done <- true
  373. }(l, rc)
  374. // Get translations at top level
  375. l.GetD("race", "My text")
  376. // Wait for goroutines to finish
  377. <-ac
  378. <-rc
  379. }
  380. func TestAddTranslator(t *testing.T) {
  381. // Create po object
  382. po := new(Po)
  383. // Parse file
  384. po.ParseFile("fixtures/en_US/default.po")
  385. // Create Locale
  386. l := NewLocale("", "en")
  387. // Add PO Translator to Locale object
  388. l.AddTranslator("default", po)
  389. // Test translations
  390. tr := l.Get("My text")
  391. if tr != "Translated text" {
  392. t.Errorf("Expected 'Translated text' but got '%s'", tr)
  393. }
  394. // Test translations
  395. tr = l.Get("language")
  396. if tr != "en_US" {
  397. t.Errorf("Expected 'en_US' but got '%s'", tr)
  398. }
  399. }
  400. func TestArabicTranslation(t *testing.T) {
  401. // Create Locale
  402. l := NewLocale("fixtures/", "ar")
  403. // Add domain
  404. l.AddDomain("categories")
  405. // Plurals formula missing + Plural translation string missing
  406. tr := l.GetD("categories", "Alcohol & Tobacco")
  407. if tr != "الكحول والتبغ" {
  408. t.Errorf("Expected to get 'الكحول والتبغ', but got '%s'", tr)
  409. }
  410. // Plural translation string present without translations, should get the msgid_plural
  411. tr = l.GetND("categories", "%d selected", "%d selected", 10)
  412. if tr != "%d selected" {
  413. t.Errorf("Expected to get '%%d selected', but got '%s'", tr)
  414. }
  415. //Plurals formula present + Plural translation string present and complete
  416. tr = l.GetND("categories", "Load %d more document", "Load %d more documents", 0)
  417. if tr != "حمّل %d مستندات إضافيّة" {
  418. t.Errorf("Expected to get 'msgstr[0]', but got '%s'", tr)
  419. }
  420. tr = l.GetND("categories", "Load %d more document", "Load %d more documents", 1)
  421. if tr != "حمّل مستند واحد إضافي" {
  422. t.Errorf("Expected to get 'msgstr[1]', but got '%s'", tr)
  423. }
  424. tr = l.GetND("categories", "Load %d more document", "Load %d more documents", 2)
  425. if tr != "حمّل مستندين إضافيين" {
  426. t.Errorf("Expected to get 'msgstr[2]', but got '%s'", tr)
  427. }
  428. tr = l.GetND("categories", "Load %d more document", "Load %d more documents", 6)
  429. if tr != "حمّل %d مستندات إضافيّة" {
  430. t.Errorf("Expected to get 'msgstr[3]', but got '%s'", tr)
  431. }
  432. tr = l.GetND("categories", "Load %d more document", "Load %d more documents", 116)
  433. if tr != "حمّل %d مستندا إضافيّا" {
  434. t.Errorf("Expected to get 'msgstr[4]', but got '%s'", tr)
  435. }
  436. tr = l.GetND("categories", "Load %d more document", "Load %d more documents", 102)
  437. if tr != "حمّل %d مستند إضافي" {
  438. t.Errorf("Expected to get 'msgstr[5]', but got '%s'", tr)
  439. }
  440. }
  441. func TestArabicMissingPluralForm(t *testing.T) {
  442. // Create Locale
  443. l := NewLocale("fixtures/", "ar")
  444. // Add domain
  445. l.AddDomain("no_plural_header")
  446. // Get translation
  447. tr := l.GetD("no_plural_header", "Alcohol & Tobacco")
  448. if tr != "الكحول والتبغ" {
  449. t.Errorf("Expected to get 'الكحول والتبغ', but got '%s'", tr)
  450. }
  451. }
  452. func TestLocaleBinaryEncoding(t *testing.T) {
  453. // Create Locale
  454. l := NewLocale("fixtures/", "en_US")
  455. l.AddDomain("default")
  456. buff, err := l.MarshalBinary()
  457. if err != nil {
  458. t.Fatal(err)
  459. }
  460. l2 := new(Locale)
  461. err = l2.UnmarshalBinary(buff)
  462. if err != nil {
  463. t.Fatal(err)
  464. }
  465. // Check object properties
  466. if l.path != l2.path {
  467. t.Fatalf("path doesn't match: '%s' vs '%s'", l.path, l2.path)
  468. }
  469. if l.lang != l2.lang {
  470. t.Fatalf("lang doesn't match: '%s' vs '%s'", l.lang, l2.lang)
  471. }
  472. if l.defaultDomain != l2.defaultDomain {
  473. t.Fatalf("defaultDomain doesn't match: '%s' vs '%s'", l.defaultDomain, l2.defaultDomain)
  474. }
  475. // Check translations
  476. if l.Get("My text") != l2.Get("My text") {
  477. t.Errorf("'%s' is different from '%s", l.Get("My text"), l2.Get("My text"))
  478. }
  479. if l.Get("More") != l2.Get("More") {
  480. t.Errorf("'%s' is different from '%s", l.Get("More"), l2.Get("More"))
  481. }
  482. if l.GetN("One with var: %s", "Several with vars: %s", 3, "VALUE") != l2.GetN("One with var: %s", "Several with vars: %s", 3, "VALUE") {
  483. t.Errorf("'%s' is different from '%s", l.GetN("One with var: %s", "Several with vars: %s", 3, "VALUE"), l2.GetN("One with var: %s", "Several with vars: %s", 3, "VALUE"))
  484. }
  485. }