taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

message.go (4729B)


      1 // Copyright 2015 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 
      5 package message // import "golang.org/x/text/message"
      6 
      7 import (
      8 	"io"
      9 	"os"
     10 
     11 	// Include features to facilitate generated catalogs.
     12 	_ "golang.org/x/text/feature/plural"
     13 
     14 	"golang.org/x/text/internal/number"
     15 	"golang.org/x/text/language"
     16 	"golang.org/x/text/message/catalog"
     17 )
     18 
     19 // A Printer implements language-specific formatted I/O analogous to the fmt
     20 // package.
     21 type Printer struct {
     22 	// the language
     23 	tag language.Tag
     24 
     25 	toDecimal    number.Formatter
     26 	toScientific number.Formatter
     27 
     28 	cat catalog.Catalog
     29 }
     30 
     31 type options struct {
     32 	cat catalog.Catalog
     33 	// TODO:
     34 	// - allow %s to print integers in written form (tables are likely too large
     35 	//   to enable this by default).
     36 	// - list behavior
     37 	//
     38 }
     39 
     40 // An Option defines an option of a Printer.
     41 type Option func(o *options)
     42 
     43 // Catalog defines the catalog to be used.
     44 func Catalog(c catalog.Catalog) Option {
     45 	return func(o *options) { o.cat = c }
     46 }
     47 
     48 // NewPrinter returns a Printer that formats messages tailored to language t.
     49 func NewPrinter(t language.Tag, opts ...Option) *Printer {
     50 	options := &options{
     51 		cat: DefaultCatalog,
     52 	}
     53 	for _, o := range opts {
     54 		o(options)
     55 	}
     56 	p := &Printer{
     57 		tag: t,
     58 		cat: options.cat,
     59 	}
     60 	p.toDecimal.InitDecimal(t)
     61 	p.toScientific.InitScientific(t)
     62 	return p
     63 }
     64 
     65 // Sprint is like fmt.Sprint, but using language-specific formatting.
     66 func (p *Printer) Sprint(a ...interface{}) string {
     67 	pp := newPrinter(p)
     68 	pp.doPrint(a)
     69 	s := pp.String()
     70 	pp.free()
     71 	return s
     72 }
     73 
     74 // Fprint is like fmt.Fprint, but using language-specific formatting.
     75 func (p *Printer) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
     76 	pp := newPrinter(p)
     77 	pp.doPrint(a)
     78 	n64, err := io.Copy(w, &pp.Buffer)
     79 	pp.free()
     80 	return int(n64), err
     81 }
     82 
     83 // Print is like fmt.Print, but using language-specific formatting.
     84 func (p *Printer) Print(a ...interface{}) (n int, err error) {
     85 	return p.Fprint(os.Stdout, a...)
     86 }
     87 
     88 // Sprintln is like fmt.Sprintln, but using language-specific formatting.
     89 func (p *Printer) Sprintln(a ...interface{}) string {
     90 	pp := newPrinter(p)
     91 	pp.doPrintln(a)
     92 	s := pp.String()
     93 	pp.free()
     94 	return s
     95 }
     96 
     97 // Fprintln is like fmt.Fprintln, but using language-specific formatting.
     98 func (p *Printer) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
     99 	pp := newPrinter(p)
    100 	pp.doPrintln(a)
    101 	n64, err := io.Copy(w, &pp.Buffer)
    102 	pp.free()
    103 	return int(n64), err
    104 }
    105 
    106 // Println is like fmt.Println, but using language-specific formatting.
    107 func (p *Printer) Println(a ...interface{}) (n int, err error) {
    108 	return p.Fprintln(os.Stdout, a...)
    109 }
    110 
    111 // Sprintf is like fmt.Sprintf, but using language-specific formatting.
    112 func (p *Printer) Sprintf(key Reference, a ...interface{}) string {
    113 	pp := newPrinter(p)
    114 	lookupAndFormat(pp, key, a)
    115 	s := pp.String()
    116 	pp.free()
    117 	return s
    118 }
    119 
    120 // Fprintf is like fmt.Fprintf, but using language-specific formatting.
    121 func (p *Printer) Fprintf(w io.Writer, key Reference, a ...interface{}) (n int, err error) {
    122 	pp := newPrinter(p)
    123 	lookupAndFormat(pp, key, a)
    124 	n, err = w.Write(pp.Bytes())
    125 	pp.free()
    126 	return n, err
    127 
    128 }
    129 
    130 // Printf is like fmt.Printf, but using language-specific formatting.
    131 func (p *Printer) Printf(key Reference, a ...interface{}) (n int, err error) {
    132 	pp := newPrinter(p)
    133 	lookupAndFormat(pp, key, a)
    134 	n, err = os.Stdout.Write(pp.Bytes())
    135 	pp.free()
    136 	return n, err
    137 }
    138 
    139 func lookupAndFormat(p *printer, r Reference, a []interface{}) {
    140 	p.fmt.Reset(a)
    141 	switch v := r.(type) {
    142 	case string:
    143 		if p.catContext.Execute(v) == catalog.ErrNotFound {
    144 			p.Render(v)
    145 			return
    146 		}
    147 	case key:
    148 		if p.catContext.Execute(v.id) == catalog.ErrNotFound &&
    149 			p.catContext.Execute(v.fallback) == catalog.ErrNotFound {
    150 			p.Render(v.fallback)
    151 			return
    152 		}
    153 	default:
    154 		panic("key argument is not a Reference")
    155 	}
    156 }
    157 
    158 type rawPrinter struct {
    159 	p *printer
    160 }
    161 
    162 func (p rawPrinter) Render(msg string)     { p.p.WriteString(msg) }
    163 func (p rawPrinter) Arg(i int) interface{} { return nil }
    164 
    165 // Arg implements catmsg.Renderer.
    166 func (p *printer) Arg(i int) interface{} { // TODO, also return "ok" bool
    167 	i--
    168 	if uint(i) < uint(len(p.fmt.Args)) {
    169 		return p.fmt.Args[i]
    170 	}
    171 	return nil
    172 }
    173 
    174 // Render implements catmsg.Renderer.
    175 func (p *printer) Render(msg string) {
    176 	p.doPrintf(msg)
    177 }
    178 
    179 // A Reference is a string or a message reference.
    180 type Reference interface {
    181 	// TODO: also allow []string
    182 }
    183 
    184 // Key creates a message Reference for a message where the given id is used for
    185 // message lookup and the fallback is returned when no matches are found.
    186 func Key(id string, fallback string) Reference {
    187 	return key{id, fallback}
    188 }
    189 
    190 type key struct {
    191 	id, fallback string
    192 }