aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Carlos <jose.carlos@menteslibres.net>2016-02-20 07:33:14 -0600
committerJosé Carlos <jose.carlos@menteslibres.net>2016-02-20 07:33:14 -0600
commitea584c8c09c390260b68a9e1a15d60f7ffe480c5 (patch)
treed84ea7ec068b7998adae2bd4580db9dc78584c56
parentMerge branch 'master' of github.com:gosexy/gettext (diff)
parentCode cleaning. (diff)
downloadgotext-ea584c8c09c390260b68a9e1a15d60f7ffe480c5.tar.gz
gotext-ea584c8c09c390260b68a9e1a15d60f7ffe480c5.tar.xz
Merge pull request #9 from gosexy/issue-5
Code cleaning.
-rw-r--r--.gitignore1
-rw-r--r--LICENSE2
-rw-r--r--README.md30
-rw-r--r--_examples/de_DE.utf8/LC_MESSAGES/example.mo (renamed from examples/de_DE.utf8/LC_MESSAGES/example.mo)bin606 -> 614 bytes
-rw-r--r--_examples/de_DE.utf8/example.pot (renamed from examples/de_DE.utf8/example.pot)2
-rw-r--r--_examples/es_MX.utf8/LC_MESSAGES/example.mo (renamed from examples/es_MX.utf8/LC_MESSAGES/example.mo)bin614 -> 614 bytes
-rw-r--r--_examples/es_MX.utf8/example.pot (renamed from examples/es_MX.utf8/example.pot)0
-rw-r--r--_examples/gettext.go (renamed from examples/gettext.go)0
-rw-r--r--gettext.go215
-rw-r--r--gettext_test.go165
10 files changed, 160 insertions, 255 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..45d62d8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.sw?
diff --git a/LICENSE b/LICENSE
index 92a8fde..822e787 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2012-2013 José Carlos Nieto, http://xiam.menteslibres.org/
+Copyright (c) 2012-2016 José Carlos Nieto, https://menteslibres.net/xiam
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/README.md b/README.md
index 8516a5f..a916b4b 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,22 @@ library for writing multilingual systems.
## Requeriments
-The GNU C library. If you're using GNU/Linux, FreeBSD or OSX you probably
-already have it.
+* [GNU gettext][1]
+
+### OSX
+
+Installing gettext on a Mac is a bit awkward:
+
+```
+brew install gettext
+
+export CGO_LDFLAGS=-L/usr/local/opt/gettext/lib
+export CGO_CPPFLAGS=-I/usr/local/opt/gettext/include
+
+go get github.com/gosexy/gettext
+```
+
+Installation should be straightforward on Linux.
## Installation
@@ -25,18 +39,18 @@ This is an example program showing the `BindTextdomain`, `Textdomain` and
package main
import (
- "github.com/gosexy/gettext"
"fmt"
- "os"
+
+ "github.com/gosexy/gettext"
)
func main() {
- gettext.BindTextdomain("example", ".")
- gettext.Textdomain("example")
+ textDomain := "default"
- os.Setenv("LANGUAGE", "es_MX.utf8")
+ gettext.BindTextdomain(textDomain, "path/to/domains")
+ gettext.Textdomain(textDomain)
- gettext.SetLocale(gettext.LC_ALL, "")
+ gettext.SetLocale(gettext.LcAll, "es_MX.utf8")
fmt.Println(gettext.Gettext("Hello, world!"))
}
diff --git a/examples/de_DE.utf8/LC_MESSAGES/example.mo b/_examples/de_DE.utf8/LC_MESSAGES/example.mo
index 36cc2a3..9c8c27d 100644
--- a/examples/de_DE.utf8/LC_MESSAGES/example.mo
+++ b/_examples/de_DE.utf8/LC_MESSAGES/example.mo
Binary files differ
diff --git a/examples/de_DE.utf8/example.pot b/_examples/de_DE.utf8/example.pot
index 4afd100..9261267 100644
--- a/examples/de_DE.utf8/example.pot
+++ b/_examples/de_DE.utf8/example.pot
@@ -26,7 +26,7 @@ msgstr[1] "%d Äpfel"
#: gettext_test.go:56
msgid "Good bye!"
-msgstr "Aufwiedersehen!"
+msgstr "Auf Wiedersehen!"
#: gettext_test.go:48
msgid "Good morning"
diff --git a/examples/es_MX.utf8/LC_MESSAGES/example.mo b/_examples/es_MX.utf8/LC_MESSAGES/example.mo
index ce1ebca..ce1ebca 100644
--- a/examples/es_MX.utf8/LC_MESSAGES/example.mo
+++ b/_examples/es_MX.utf8/LC_MESSAGES/example.mo
Binary files differ
diff --git a/examples/es_MX.utf8/example.pot b/_examples/es_MX.utf8/example.pot
index b490af0..b490af0 100644
--- a/examples/es_MX.utf8/example.pot
+++ b/_examples/es_MX.utf8/example.pot
diff --git a/examples/gettext.go b/_examples/gettext.go
index a01e0d5..a01e0d5 100644
--- a/examples/gettext.go
+++ b/_examples/gettext.go
diff --git a/gettext.go b/gettext.go
index 624ab34..4550ba1 100644
--- a/gettext.go
+++ b/gettext.go
@@ -1,31 +1,30 @@
-/*
- Copyright (c) 2012 José Carlos Nieto, http://xiam.menteslibres.org/
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
+// Copyright (c) 2012-2016 José Carlos Nieto, https://menteslibres.net/xiam
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Package gettext provides bindings for GNU Gettext.
package gettext
/*
-
#include <libintl.h>
+
#include <locale.h>
#include <stdlib.h>
*/
@@ -38,127 +37,117 @@ import (
)
var (
- // For all of the locale.
- LC_ALL = uint(C.LC_ALL)
+ // LcAll is for all of the locale.
+ LcAll = uint(C.LC_ALL)
- // For regular expression matching (it determines the meaning of range
- // expressions and equivalence classes) and string collation.
- LC_COLATE = uint(C.LC_ALL)
+ // LcColate is for regular expression matching (it determines the meaning of
+ // range expressions and equivalence classes) and string collation.
+ LcColate = uint(C.LC_ALL)
- // For regular expression matching, character classification, conversion,
- // case-sensitive comparison, and wide character functions.
- LC_CTYPE = uint(C.LC_CTYPE)
+ // LcCtype is for regular expression matching, character classification,
+ // conversion, case-sensitive comparison, and wide character functions.
+ LcCtype = uint(C.LC_CTYPE)
- // For localizable natural-language messages.
- LC_MESSAGES = uint(C.LC_MESSAGES)
+ // LcMessages is for localizable natural-language messages.
+ LcMessages = uint(C.LC_MESSAGES)
- // For monetary formatting.
- LC_MONETARY = uint(C.LC_MONETARY)
+ // LcMonetary is for monetary formatting.
+ LcMonetary = uint(C.LC_MONETARY)
- // For number formatting (such as the decimal point and the thousands
- // separator).
- LC_NUMERIC = uint(C.LC_NUMERIC)
+ // LcNumeric is for number formatting (such as the decimal point and the
+ // thousands separator).
+ LcNumeric = uint(C.LC_NUMERIC)
- // For time and date formatting.
- LC_TIME = uint(C.LC_TIME)
+ // LcTime is for time and date formatting.
+ LcTime = uint(C.LC_TIME)
)
-// Sets or queries the program's current locale.
+// SetLocale sets the program's current locale.
func SetLocale(category uint, locale string) string {
clocale := C.CString(locale)
+ defer C.free(unsafe.Pointer(clocale))
- res := C.GoString(C.setlocale(C.int(category), clocale))
-
- C.free(unsafe.Pointer(clocale))
- return res
+ return C.GoString(C.setlocale(C.int(category), clocale))
}
-// Sets directory containing message catalogs.
+// BindTextdomain sets the directory containing message catalogs.
func BindTextdomain(domainname string, dirname string) string {
cdirname := C.CString(dirname)
- cdomainname := C.CString(domainname)
+ defer C.free(unsafe.Pointer(cdirname))
- res := C.GoString(C.bindtextdomain(cdomainname, cdirname))
+ cdomainname := C.CString(domainname)
+ defer C.free(unsafe.Pointer(cdomainname))
- C.free(unsafe.Pointer(cdirname))
- C.free(unsafe.Pointer(cdomainname))
- return res
+ return C.GoString(C.bindtextdomain(cdomainname, cdirname))
}
-// Sets the output codeset for message catalogs for domain domainname.
+// BindTextdomainCodeset sets the output codeset for message catalogs on the
+// given domainname.
func BindTextdomainCodeset(domainname string, codeset string) string {
cdomainname := C.CString(domainname)
- ccodeset := C.CString(codeset)
+ defer C.free(unsafe.Pointer(cdomainname))
- res := C.GoString(C.bind_textdomain_codeset(cdomainname, ccodeset))
+ ccodeset := C.CString(codeset)
+ defer C.free(unsafe.Pointer(ccodeset))
- C.free(unsafe.Pointer(cdomainname))
- C.free(unsafe.Pointer(ccodeset))
- return res
+ return C.GoString(C.bind_textdomain_codeset(cdomainname, ccodeset))
}
-// Sets or retrieves the current message domain.
+// Textdomain sets or retrieves the current message domain.
func Textdomain(domainname string) string {
cdomainname := C.CString(domainname)
+ defer C.free(unsafe.Pointer(cdomainname))
- res := C.GoString(C.textdomain(cdomainname))
-
- C.free(unsafe.Pointer(cdomainname))
- return res
+ return C.GoString(C.textdomain(cdomainname))
}
-// Attempt to translate a text string into the user's native language, by
-// looking up the translation in a message catalog.
+// Gettext attempts to translate a text string into the user's system language,
+// by looking up the translation in a message catalog.
func Gettext(msgid string) string {
cmsgid := C.CString(msgid)
+ defer C.free(unsafe.Pointer(cmsgid))
- res := C.GoString(C.gettext(cmsgid))
-
- C.free(unsafe.Pointer(cmsgid))
- return res
+ return C.GoString(C.gettext(cmsgid))
}
-// Like Gettext(), but looking up the message in the specified domain.
+// DGettext is like Gettext(), but looks up the message in the specified
+// domain.
func DGettext(domain string, msgid string) string {
cdomain := cDomainName(domain)
- cmsgid := C.CString(msgid)
+ defer C.free(unsafe.Pointer(cdomain))
- res := C.GoString(C.dgettext(cdomain, cmsgid))
+ cmsgid := C.CString(msgid)
+ defer C.free(unsafe.Pointer(cmsgid))
- C.free(unsafe.Pointer(cdomain))
- C.free(unsafe.Pointer(cmsgid))
- return res
+ return C.GoString(C.dgettext(cdomain, cmsgid))
}
-// Like Gettext(), but looking up the message in the specified domain and
-// category.
+// DCGettext is like Gettext(), but looks up the message in the specified
+// domain and category.
func DCGettext(domain string, msgid string, category uint) string {
cdomain := cDomainName(domain)
- cmsgid := C.CString(msgid)
+ defer C.free(unsafe.Pointer(cdomain))
- res := C.GoString(C.dcgettext(cdomain, cmsgid, C.int(category)))
+ cmsgid := C.CString(msgid)
+ defer C.free(unsafe.Pointer(cmsgid))
- C.free(unsafe.Pointer(cdomain))
- C.free(unsafe.Pointer(cmsgid))
- return res
+ return C.GoString(C.dcgettext(cdomain, cmsgid, C.int(category)))
}
-// Attempt to translate a text string into the user's native language, by
-// looking up the appropriate plural form of the translation in a message
-// catalog.
-func NGettext(msgid string, msgid_plural string, n uint64) string {
+// NGettext attempts to translate a text string into the user's system
+// language, by looking up the appropriate plural form of the translation in a
+// message catalog.
+func NGettext(msgid string, msgidPlural string, n uint64) string {
cmsgid := C.CString(msgid)
- cmsgid_plural := C.CString(msgid_plural)
-
- res := C.GoString(C.ngettext(cmsgid, cmsgid_plural, C.ulong(n)))
+ defer C.free(unsafe.Pointer(cmsgid))
- C.free(unsafe.Pointer(cmsgid))
- C.free(unsafe.Pointer(cmsgid_plural))
+ cmsgidPlural := C.CString(msgidPlural)
+ defer C.free(unsafe.Pointer(cmsgidPlural))
- return res
+ return C.GoString(C.ngettext(cmsgid, cmsgidPlural, C.ulong(n)))
}
-// Like fmt.Sprintf() but without %!(EXTRA) errors.
+// Sprintf is like fmt.Sprintf() but without %!(EXTRA) errors.
func Sprintf(format string, a ...interface{}) string {
expects := strings.Count(format, "%") - strings.Count(format, "%%")
@@ -175,35 +164,36 @@ func Sprintf(format string, a ...interface{}) string {
return format
}
-// Like NGettext(), but looking up the message in the specified domain.
-func DNGettext(domainname string, msgid string, msgid_plural string, n uint64) string {
+// DNGettext is like NGettext(), but looks up the message in the specified
+// domain.
+func DNGettext(domainname string, msgid string, msgidPlural string, n uint64) string {
cdomainname := cDomainName(domainname)
cmsgid := C.CString(msgid)
- cmsgid_plural := C.CString(msgid_plural)
+ cmsgidPlural := C.CString(msgidPlural)
- res := C.GoString(C.dngettext(cdomainname, cmsgid, cmsgid_plural, C.ulong(n)))
+ defer func() {
+ C.free(unsafe.Pointer(cdomainname))
+ C.free(unsafe.Pointer(cmsgid))
+ C.free(unsafe.Pointer(cmsgidPlural))
+ }()
- C.free(unsafe.Pointer(cdomainname))
- C.free(unsafe.Pointer(cmsgid))
- C.free(unsafe.Pointer(cmsgid_plural))
-
- return res
+ return C.GoString(C.dngettext(cdomainname, cmsgid, cmsgidPlural, C.ulong(n)))
}
-// Like NGettext(), but looking up the message in the specified domain and
-// category.
-func DCNGettext(domainname string, msgid string, msgid_plural string, n uint64, category uint) string {
+// DCNGettext is like NGettext(), but looks up the message in the specified
+// domain and category.
+func DCNGettext(domainname string, msgid string, msgidPlural string, n uint64, category uint) string {
cdomainname := cDomainName(domainname)
cmsgid := C.CString(msgid)
- cmsgid_plural := C.CString(msgid_plural)
-
- res := C.GoString(C.dcngettext(cdomainname, cmsgid, cmsgid_plural, C.ulong(n), C.int(category)))
+ cmsgidPlural := C.CString(msgidPlural)
- C.free(unsafe.Pointer(cdomainname))
- C.free(unsafe.Pointer(cmsgid))
- C.free(unsafe.Pointer(cmsgid_plural))
+ defer func() {
+ C.free(unsafe.Pointer(cdomainname))
+ C.free(unsafe.Pointer(cmsgid))
+ C.free(unsafe.Pointer(cmsgidPlural))
+ }()
- return res
+ return C.GoString(C.dcngettext(cdomainname, cmsgid, cmsgidPlural, C.ulong(n), C.int(category)))
}
// cDomainName returns the domain name CString that can be nil.
@@ -211,5 +201,6 @@ func cDomainName(domain string) *C.char {
if domain == "" {
return nil
}
+ // The caller is responsible for freeing this up.
return C.CString(domain)
}
diff --git a/gettext_test.go b/gettext_test.go
index 8e88180..6c58ab3 100644
--- a/gettext_test.go
+++ b/gettext_test.go
@@ -1,163 +1,62 @@
package gettext
import (
- "fmt"
- "os"
"testing"
-)
-
-/*
- NOTE:
-
- xgettext does not officially support Go syntax, however, you can generate a valid .pot file by forcing
- xgettest to use the C++ syntax:
-
- % xgettext -d example -s gettext_test.go -o example.pot -L c++ -i --keyword=NGettext:1,2 --keyword=Gettext
-
- This will generate a example.pot file.
-
- After translating the .pot file, you must generate .po and .mo files.
-
- Remember to set the UTF-8 charset.
-
- % msginit -l es_MX -o example.po -i example.pot
- % msgfmt -c -v -o example.mo example.po
-
- And finally, move the .mo file to an appropriate location.
-
- % mv example.mo examples/es_MX.utf8/LC_MESSAGES/example.mo
-
-*/
-
-func TestSpanishMexico(t *testing.T) {
-
- os.Setenv("LANGUAGE", "es_MX.utf8")
-
- SetLocale(LC_ALL, "")
- BindTextdomain("example", "./examples/")
- Textdomain("example")
-
- t1 := Gettext("Hello, world!")
-
- fmt.Println(t1)
-
- if t1 != "¡Hola mundo!" {
- t.Errorf("Failed translation.")
- }
-
- t2 := Sprintf(NGettext("An apple", "%d apples", 1), 1, "garbage")
-
- fmt.Println(t2)
-
- if t2 != "Una manzana" {
- t.Errorf("Failed translation.")
- }
- t3 := Sprintf(NGettext("An apple", "%d apples", 3), 3)
+ "github.com/stretchr/testify/assert"
+)
- fmt.Println(t3)
+const (
+ spanishMexico = "es_MX.utf8"
+ deutschDeutschland = "de_DE.utf8"
+ frenchFrance = "fr_FR.utf8"
+)
- if t3 != "3 manzanas" {
- t.Errorf("Failed translation.")
- }
+func TestSpanish(t *testing.T) {
+ SetLocale(LcAll, spanishMexico)
- t4 := Gettext("Good morning")
+ textDomain := "example"
- fmt.Println(t4)
+ BindTextdomain(textDomain, "_examples/")
+ Textdomain(textDomain)
- if t4 != "Buenos días" {
- t.Errorf("Failed translation.")
- }
+ assert.Equal(t, "¡Hola mundo!", Gettext("Hello, world!"))
- t5 := Gettext("Good bye!")
+ assert.Equal(t, "Una manzana", Sprintf(NGettext("An apple", "%d apples", 1), 1, "garbage"))
- fmt.Println(t5)
+ assert.Equal(t, "3 manzanas", Sprintf(NGettext("An apple", "%d apples", 3), 3))
- if t5 != "¡Hasta luego!" {
- t.Errorf("Failed translation.")
- }
+ assert.Equal(t, "Buenos días", Gettext("Good morning"))
+ assert.Equal(t, "¡Hasta luego!", Gettext("Good bye!"))
}
-func TestGermanDeutschland(t *testing.T) {
-
- os.Setenv("LANGUAGE", "de_DE.utf8")
-
- SetLocale(LC_ALL, "")
- BindTextdomain("example", "./examples/")
- Textdomain("example")
-
- t1 := Gettext("Hello, world!")
-
- fmt.Println(t1)
-
- if t1 != "Hallo, Welt!" {
- t.Errorf("Failed translation.")
- }
-
- t2 := Sprintf(NGettext("An apple", "%d apples", 1), 1, "garbage")
-
- fmt.Println(t2)
-
- if t2 != "Ein Apfel" {
- t.Errorf("Failed translation.")
- }
+func TestDeutsch(t *testing.T) {
+ SetLocale(LcAll, deutschDeutschland)
- t3 := Sprintf(NGettext("An apple", "%d apples", 3), 3)
+ assert.Equal(t, "Hallo, Welt!", Gettext("Hello, world!"))
- fmt.Println(t3)
+ assert.Equal(t, "Ein Apfel", Sprintf(NGettext("An apple", "%d apples", 1), 1, "garbage"))
- if t3 != "3 Äpfel" {
- t.Errorf("Failed translation.")
- }
+ assert.Equal(t, "3 Äpfel", Sprintf(NGettext("An apple", "%d apples", 3), 3))
- t4 := Gettext("Good morning")
-
- fmt.Println(t4)
-
- if t4 != "Guten morgen" {
- t.Errorf("Failed translation.")
- }
-
- t5 := Gettext("Good bye!")
-
- fmt.Println(t5)
-
- if t5 != "Aufwiedersehen!" {
- t.Errorf("Failed translation.")
- }
+ assert.Equal(t, "Guten morgen", Gettext("Good morning"))
+ assert.Equal(t, "Auf Wiedersehen!", Gettext("Good bye!"))
}
-func TestDGettextFallback(t *testing.T) {
- os.Setenv("LANGUAGE", "de_DE.utf8")
-
- SetLocale(LC_ALL, "")
- BindTextdomain("example", "./examples/")
- Textdomain("example")
-
- t1 := DGettext("", "Hello, world!")
-
- fmt.Println(t1)
-
- if t1 != "Hallo, Welt!" {
- t.Errorf("Failed translation fallback.")
- }
-
- t2 := Sprintf(DNGettext("", "An apple", "%d apples", 1), 1, "garbage")
+func TestFrench(t *testing.T) {
+ // Note that we don't have a french translation.
- fmt.Println(t2)
+ SetLocale(LcAll, frenchFrance)
- if t2 != "Ein Apfel" {
- t.Errorf("Failed translation fallback.")
- }
+ assert.Equal(t, "Hello, world!", Gettext("Hello, world!"))
- t3 := Sprintf(DNGettext("", "An apple", "%d apples", 3), 3)
+ assert.Equal(t, "An apple", Sprintf(NGettext("An apple", "%d apples", 1), 1, "garbage"))
- fmt.Println(t3)
+ assert.Equal(t, "3 apples", Sprintf(NGettext("An apple", "%d apples", 3), 3))
- if t3 != "3 Äpfel" {
- t.Errorf("Failed translation fallback.")
- }
+ assert.Equal(t, "Good morning", Gettext("Good morning"))
+ assert.Equal(t, "Good bye!", Gettext("Good bye!"))
}