language: add marshaling

Change-Id: Ief87043eddd0e1fc86e1f589f55732cfa844bdfd
Reviewed-on: https://go-review.googlesource.com/80255
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/language/language.go b/language/language.go
index ed1011f..b65e213 100644
--- a/language/language.go
+++ b/language/language.go
@@ -299,6 +299,26 @@
 	return string(buf[:t.genCoreBytes(buf[:])])
 }
 
+// MarshalText implements encoding.TextMarshaler.
+func (t Tag) MarshalText() (text []byte, err error) {
+	if t.str != "" {
+		text = append(text, t.str...)
+	} else if t.script == 0 && t.region == 0 {
+		text = append(text, t.lang.String()...)
+	} else {
+		buf := [maxCoreSize]byte{}
+		text = buf[:t.genCoreBytes(buf[:])]
+	}
+	return text, nil
+}
+
+// UnmarshalText implements encoding.TextUnmarshaler.
+func (t *Tag) UnmarshalText(text []byte) error {
+	tag, err := Raw.Parse(string(text))
+	*t = tag
+	return err
+}
+
 // Base returns the base language of the language tag. If the base language is
 // unspecified, an attempt will be made to infer it from the context.
 // It uses a variant of CLDR's Add Likely Subtags algorithm. This is subject to change.
diff --git a/language/language_test.go b/language/language_test.go
index f7c2d88..684ac2e 100644
--- a/language/language_test.go
+++ b/language/language_test.go
@@ -106,6 +106,39 @@
 	}
 }
 
+func TestMarshal(t *testing.T) {
+	testCases := []string{
+		// TODO: these values will change with each CLDR update. This issue
+		// will be solved if we decide to fix the indexes.
+		"und",
+		"ca-ES-valencia",
+		"ca-ES-valencia-u-va-posix",
+		"ca-ES-valencia-u-co-phonebk",
+		"ca-ES-valencia-u-co-phonebk-va-posix",
+		"x-klingon",
+		"en-US",
+		"en-US-u-va-posix",
+		"en",
+		"en-u-co-phonebk",
+		"en-001",
+		"sh",
+	}
+	for _, tc := range testCases {
+		var tag Tag
+		err := tag.UnmarshalText([]byte(tc))
+		if err != nil {
+			t.Errorf("UnmarshalText(%q): unexpected error: %v", tc, err)
+		}
+		b, err := tag.MarshalText()
+		if err != nil {
+			t.Errorf("MarshalText(%q): unexpected error: %v", tc, err)
+		}
+		if got := string(b); got != tc {
+			t.Errorf("%s: got %q; want %q", tc, got, tc)
+		}
+	}
+}
+
 func TestBase(t *testing.T) {
 	tests := []struct {
 		loc, lang string