1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package language_test
6
7import (
8	"fmt"
9	"net/http"
10
11	"golang.org/x/text/language"
12)
13
14func ExampleCanonType() {
15	p := func(id string) {
16		fmt.Printf("Default(%s) -> %s\n", id, language.Make(id))
17		fmt.Printf("BCP47(%s) -> %s\n", id, language.BCP47.Make(id))
18		fmt.Printf("Macro(%s) -> %s\n", id, language.Macro.Make(id))
19		fmt.Printf("All(%s) -> %s\n", id, language.All.Make(id))
20	}
21	p("en-Latn")
22	p("sh")
23	p("zh-cmn")
24	p("bjd")
25	p("iw-Latn-fonipa-u-cu-usd")
26	// Output:
27	// Default(en-Latn) -> en-Latn
28	// BCP47(en-Latn) -> en
29	// Macro(en-Latn) -> en-Latn
30	// All(en-Latn) -> en
31	// Default(sh) -> sr-Latn
32	// BCP47(sh) -> sh
33	// Macro(sh) -> sh
34	// All(sh) -> sr-Latn
35	// Default(zh-cmn) -> cmn
36	// BCP47(zh-cmn) -> cmn
37	// Macro(zh-cmn) -> zh
38	// All(zh-cmn) -> zh
39	// Default(bjd) -> drl
40	// BCP47(bjd) -> drl
41	// Macro(bjd) -> bjd
42	// All(bjd) -> drl
43	// Default(iw-Latn-fonipa-u-cu-usd) -> he-Latn-fonipa-u-cu-usd
44	// BCP47(iw-Latn-fonipa-u-cu-usd) -> he-Latn-fonipa-u-cu-usd
45	// Macro(iw-Latn-fonipa-u-cu-usd) -> iw-Latn-fonipa-u-cu-usd
46	// All(iw-Latn-fonipa-u-cu-usd) -> he-Latn-fonipa-u-cu-usd
47}
48
49func ExampleTag_Base() {
50	fmt.Println(language.Make("und").Base())
51	fmt.Println(language.Make("und-US").Base())
52	fmt.Println(language.Make("und-NL").Base())
53	fmt.Println(language.Make("und-419").Base()) // Latin America
54	fmt.Println(language.Make("und-ZZ").Base())
55	// Output:
56	// en Low
57	// en High
58	// nl High
59	// es Low
60	// en Low
61}
62
63func ExampleTag_Script() {
64	en := language.Make("en")
65	sr := language.Make("sr")
66	sr_Latn := language.Make("sr_Latn")
67	fmt.Println(en.Script())
68	fmt.Println(sr.Script())
69	// Was a script explicitly specified?
70	_, c := sr.Script()
71	fmt.Println(c == language.Exact)
72	_, c = sr_Latn.Script()
73	fmt.Println(c == language.Exact)
74	// Output:
75	// Latn High
76	// Cyrl Low
77	// false
78	// true
79}
80
81func ExampleTag_Region() {
82	ru := language.Make("ru")
83	en := language.Make("en")
84	fmt.Println(ru.Region())
85	fmt.Println(en.Region())
86	// Output:
87	// RU Low
88	// US Low
89}
90
91func ExampleRegion_TLD() {
92	us := language.MustParseRegion("US")
93	gb := language.MustParseRegion("GB")
94	uk := language.MustParseRegion("UK")
95	bu := language.MustParseRegion("BU")
96
97	fmt.Println(us.TLD())
98	fmt.Println(gb.TLD())
99	fmt.Println(uk.TLD())
100	fmt.Println(bu.TLD())
101
102	fmt.Println(us.Canonicalize().TLD())
103	fmt.Println(gb.Canonicalize().TLD())
104	fmt.Println(uk.Canonicalize().TLD())
105	fmt.Println(bu.Canonicalize().TLD())
106	// Output:
107	// US <nil>
108	// UK <nil>
109	// UK <nil>
110	// ZZ language: region is not a valid ccTLD
111	// US <nil>
112	// UK <nil>
113	// UK <nil>
114	// MM <nil>
115}
116
117func ExampleCompose() {
118	nl, _ := language.ParseBase("nl")
119	us, _ := language.ParseRegion("US")
120	de := language.Make("de-1901-u-co-phonebk")
121	jp := language.Make("ja-JP")
122	fi := language.Make("fi-x-ing")
123
124	u, _ := language.ParseExtension("u-nu-arabic")
125	x, _ := language.ParseExtension("x-piglatin")
126
127	// Combine a base language and region.
128	fmt.Println(language.Compose(nl, us))
129	// Combine a base language and extension.
130	fmt.Println(language.Compose(nl, x))
131	// Replace the region.
132	fmt.Println(language.Compose(jp, us))
133	// Combine several tags.
134	fmt.Println(language.Compose(us, nl, u))
135
136	// Replace the base language of a tag.
137	fmt.Println(language.Compose(de, nl))
138	fmt.Println(language.Compose(de, nl, u))
139	// Remove the base language.
140	fmt.Println(language.Compose(de, language.Base{}))
141	// Remove all variants.
142	fmt.Println(language.Compose(de, []language.Variant{}))
143	// Remove all extensions.
144	fmt.Println(language.Compose(de, []language.Extension{}))
145	fmt.Println(language.Compose(fi, []language.Extension{}))
146	// Remove all variants and extensions.
147	fmt.Println(language.Compose(de.Raw()))
148
149	// An error is gobbled or returned if non-nil.
150	fmt.Println(language.Compose(language.ParseRegion("ZA")))
151	fmt.Println(language.Compose(language.ParseRegion("HH")))
152
153	// Compose uses the same Default canonicalization as Make.
154	fmt.Println(language.Compose(language.Raw.Parse("en-Latn-UK")))
155
156	// Call compose on a different CanonType for different results.
157	fmt.Println(language.All.Compose(language.Raw.Parse("en-Latn-UK")))
158
159	// Output:
160	// nl-US <nil>
161	// nl-x-piglatin <nil>
162	// ja-US <nil>
163	// nl-US-u-nu-arabic <nil>
164	// nl-1901-u-co-phonebk <nil>
165	// nl-1901-u-co-phonebk-nu-arabic <nil>
166	// und-1901-u-co-phonebk <nil>
167	// de-u-co-phonebk <nil>
168	// de-1901 <nil>
169	// fi <nil>
170	// de <nil>
171	// und-ZA <nil>
172	// und language: subtag "HH" is well-formed but unknown
173	// en-Latn-GB <nil>
174	// en-GB <nil>
175}
176
177func ExampleParse_errors() {
178	for _, s := range []string{"Foo", "Bar", "Foobar"} {
179		_, err := language.Parse(s)
180		if err != nil {
181			if inv, ok := err.(language.ValueError); ok {
182				fmt.Println(inv.Subtag())
183			} else {
184				fmt.Println(s)
185			}
186		}
187	}
188	for _, s := range []string{"en", "aa-Uuuu", "AC", "ac-u"} {
189		_, err := language.Parse(s)
190		switch e := err.(type) {
191		case language.ValueError:
192			fmt.Printf("%s: culprit %q\n", s, e.Subtag())
193		case nil:
194			// No error.
195		default:
196			// A syntax error.
197			fmt.Printf("%s: ill-formed\n", s)
198		}
199	}
200	// Output:
201	// foo
202	// Foobar
203	// aa-Uuuu: culprit "Uuuu"
204	// AC: culprit "ac"
205	// ac-u: ill-formed
206}
207
208func ExampleParent() {
209	p := func(tag string) {
210		fmt.Printf("parent(%v): %v\n", tag, language.Make(tag).Parent())
211	}
212	p("zh-CN")
213
214	// Australian English inherits from World English.
215	p("en-AU")
216
217	// If the tag has a different maximized script from its parent, a tag with
218	// this maximized script is inserted. This allows different language tags
219	// which have the same base language and script in common to inherit from
220	// a common set of settings.
221	p("zh-HK")
222
223	// If the maximized script of the parent is not identical, CLDR will skip
224	// inheriting from it, as it means there will not be many entries in common
225	// and inheriting from it is nonsensical.
226	p("zh-Hant")
227
228	// The parent of a tag with variants and extensions is the tag with all
229	// variants and extensions removed.
230	p("de-1994-u-co-phonebk")
231
232	// Remove default script.
233	p("de-Latn-LU")
234
235	// Output:
236	// parent(zh-CN): zh
237	// parent(en-AU): en-001
238	// parent(zh-HK): zh-Hant
239	// parent(zh-Hant): und
240	// parent(de-1994-u-co-phonebk): de
241	// parent(de-Latn-LU): de
242}
243
244// ExampleMatcher_bestMatch gives some examples of getting the best match of
245// a set of tags to any of the tags of given set.
246func ExampleMatcher() {
247	// This is the set of tags from which we want to pick the best match. These
248	// can be, for example, the supported languages for some package.
249	tags := []language.Tag{
250		language.English,
251		language.BritishEnglish,
252		language.French,
253		language.Afrikaans,
254		language.BrazilianPortuguese,
255		language.EuropeanPortuguese,
256		language.Croatian,
257		language.SimplifiedChinese,
258		language.Raw.Make("iw-IL"),
259		language.Raw.Make("iw"),
260		language.Raw.Make("he"),
261	}
262	m := language.NewMatcher(tags)
263
264	// A simple match.
265	fmt.Println(m.Match(language.Make("fr")))
266
267	// Australian English is closer to British than American English.
268	fmt.Println(m.Match(language.Make("en-AU")))
269
270	// Default to the first tag passed to the Matcher if there is no match.
271	fmt.Println(m.Match(language.Make("ar")))
272
273	// Get the default tag.
274	fmt.Println(m.Match())
275
276	fmt.Println("----")
277
278	// Someone specifying sr-Latn is probably fine with getting Croatian.
279	fmt.Println(m.Match(language.Make("sr-Latn")))
280
281	// We match SimplifiedChinese, but with Low confidence.
282	fmt.Println(m.Match(language.TraditionalChinese))
283
284	// Serbian in Latin script is a closer match to Croatian than Traditional
285	// Chinese to Simplified Chinese.
286	fmt.Println(m.Match(language.TraditionalChinese, language.Make("sr-Latn")))
287
288	fmt.Println("----")
289
290	// In case a multiple variants of a language are available, the most spoken
291	// variant is typically returned.
292	fmt.Println(m.Match(language.Portuguese))
293
294	// Pick the first value passed to Match in case of a tie.
295	fmt.Println(m.Match(language.Dutch, language.Make("fr-BE"), language.Make("af-NA")))
296	fmt.Println(m.Match(language.Dutch, language.Make("af-NA"), language.Make("fr-BE")))
297
298	fmt.Println("----")
299
300	// If a Matcher is initialized with a language and it's deprecated version,
301	// it will distinguish between them.
302	fmt.Println(m.Match(language.Raw.Make("iw")))
303
304	// However, for non-exact matches, it will treat deprecated versions as
305	// equivalent and consider other factors first.
306	fmt.Println(m.Match(language.Raw.Make("he-IL")))
307
308	fmt.Println("----")
309
310	// User settings passed to the Unicode extension are ignored for matching
311	// and preserved in the returned tag.
312	fmt.Println(m.Match(language.Make("de-u-co-phonebk"), language.Make("fr-u-cu-frf")))
313
314	// Even if the matching language is different.
315	fmt.Println(m.Match(language.Make("de-u-co-phonebk"), language.Make("br-u-cu-frf")))
316
317	// If there is no matching language, the options of the first preferred tag are used.
318	fmt.Println(m.Match(language.Make("de-u-co-phonebk")))
319
320	// Output:
321	// fr 2 Exact
322	// en-GB 1 High
323	// en 0 No
324	// en 0 No
325	// ----
326	// hr 6 High
327	// zh-Hans 7 Low
328	// hr 6 High
329	// ----
330	// pt-BR 4 High
331	// fr 2 High
332	// af 3 High
333	// ----
334	// iw 9 Exact
335	// he 10 Exact
336	// ----
337	// fr-u-cu-frf 2 Exact
338	// fr-u-cu-frf 2 High
339	// en-u-co-phonebk 0 No
340
341	// TODO: "he" should be "he-u-rg-IL High"
342}
343
344func ExampleMatchStrings() {
345	// languages supported by this service:
346	matcher := language.NewMatcher([]language.Tag{
347		language.English, language.Dutch, language.German,
348	})
349
350	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
351		lang, _ := r.Cookie("lang")
352		tag, _ := language.MatchStrings(matcher, lang.String(), r.Header.Get("Accept-Language"))
353
354		fmt.Println("User language:", tag)
355	})
356}
357
358func ExampleComprehends() {
359	// Various levels of comprehensibility.
360	fmt.Println(language.Comprehends(language.English, language.English))
361	fmt.Println(language.Comprehends(language.AmericanEnglish, language.BritishEnglish))
362
363	// An explicit Und results in no match.
364	fmt.Println(language.Comprehends(language.English, language.Und))
365
366	fmt.Println("----")
367
368	// There is usually no mutual comprehensibility between different scripts.
369	fmt.Println(language.Comprehends(language.Make("en-Dsrt"), language.English))
370
371	// One exception is for Traditional versus Simplified Chinese, albeit with
372	// a low confidence.
373	fmt.Println(language.Comprehends(language.TraditionalChinese, language.SimplifiedChinese))
374
375	fmt.Println("----")
376
377	// A Swiss German speaker will often understand High German.
378	fmt.Println(language.Comprehends(language.Make("gsw"), language.Make("de")))
379
380	// The converse is not generally the case.
381	fmt.Println(language.Comprehends(language.Make("de"), language.Make("gsw")))
382
383	// Output:
384	// Exact
385	// High
386	// No
387	// ----
388	// No
389	// Low
390	// ----
391	// High
392	// No
393}
394
395func ExampleTag_values() {
396	us := language.MustParseRegion("US")
397	en := language.MustParseBase("en")
398
399	lang, _, region := language.AmericanEnglish.Raw()
400	fmt.Println(lang == en, region == us)
401
402	lang, _, region = language.BritishEnglish.Raw()
403	fmt.Println(lang == en, region == us)
404
405	// Tags can be compared for exact equivalence using '=='.
406	en_us, _ := language.Compose(en, us)
407	fmt.Println(en_us == language.AmericanEnglish)
408
409	// Output:
410	// true true
411	// true false
412	// true
413}
414