decred.org/dcrdex@v1.0.5/client/cmd/translationsreport/main.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"flag"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"decred.org/dcrdex/client/core"
    13  	"decred.org/dcrdex/client/intl"
    14  	"decred.org/dcrdex/client/webserver"
    15  	"decred.org/dcrdex/client/webserver/locales"
    16  	"decred.org/dcrdex/dex"
    17  )
    18  
    19  func main() {
    20  	if err := mainErr(); err != nil {
    21  		fmt.Fprint(os.Stderr, err, "\n")
    22  		os.Exit(1)
    23  	}
    24  	os.Exit(0)
    25  }
    26  
    27  func mainErr() error {
    28  	var formatFile string
    29  	flag.StringVar(&formatFile, "format", "", "filename. format the completed translation report for Go and print to stdout then quit")
    30  	flag.Parse()
    31  
    32  	if formatFile != "" {
    33  		return formatReport(formatFile)
    34  	}
    35  
    36  	core.RegisterTranslations()
    37  	webserver.RegisterTranslations()
    38  	locales.RegisterTranslations()
    39  
    40  	reports := intl.Report()
    41  	if err := os.MkdirAll("worksheets", 0755); err != nil {
    42  		return fmt.Errorf("error making worksheets directory: %v", err)
    43  	}
    44  
    45  	for lang, r := range reports {
    46  		if lang == "en-US" {
    47  			continue
    48  		}
    49  		worksheet := make([]*WorksheetEntry, 0)
    50  		for callerID, ts := range r.Missing {
    51  			for translationID, t := range ts {
    52  				worksheet = append(worksheet, &WorksheetEntry{
    53  					ID:      translationID,
    54  					Version: t.Version,
    55  					Context: callerID,
    56  					Notes:   t.Notes,
    57  					English: t.T,
    58  				})
    59  			}
    60  		}
    61  
    62  		worksheetPath := filepath.Join("worksheets", lang+".json")
    63  		f, err := os.OpenFile(worksheetPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
    64  		if err != nil {
    65  			return fmt.Errorf("OpenFile(%q) error: %w", worksheetPath, err)
    66  		}
    67  
    68  		enc := json.NewEncoder(f)
    69  		enc.SetEscapeHTML(false) // This is why we're using json.Encoder
    70  		enc.SetIndent("", "    ")
    71  		err = enc.Encode(worksheet)
    72  		f.Close()
    73  		if err != nil {
    74  			return fmt.Errorf("json encode error: %w", err)
    75  		}
    76  	}
    77  	return nil
    78  }
    79  
    80  type WorksheetEntry struct {
    81  	ID          string `json:"id"`
    82  	Version     int    `json:"version,omitempty"`
    83  	Context     string `json:"context"`
    84  	Notes       string `json:"notes,omitempty"`
    85  	English     string `json:"english"`
    86  	Translation string `json:"translation"`
    87  }
    88  
    89  func formatReport(reportFile string) error {
    90  	b, err := os.ReadFile(dex.CleanAndExpandPath(reportFile))
    91  	if err != nil {
    92  		return fmt.Errorf("error reading file at %q: %w", reportFile, err)
    93  	}
    94  	var entries []*WorksheetEntry
    95  	if err := json.Unmarshal(b, &entries); err != nil {
    96  		return fmt.Errorf("JSON error for report file at %q: %w", reportFile, err)
    97  	}
    98  	sortedEntries := make(map[string][]*WorksheetEntry, 3)
    99  	entryErrs := make([]string, 0)
   100  	for _, e := range entries {
   101  		if e.Context == "" {
   102  			entryErrs = append(entryErrs, fmt.Sprintf("no context found for report with ID %q", e.ID))
   103  			continue
   104  		}
   105  		sortedEntries[e.Context] = append(sortedEntries[e.Context], e)
   106  	}
   107  
   108  	entryErrs = append(entryErrs, printCoreLines(sortedEntries["notifications"])...)
   109  	entryErrs = append(entryErrs, printJSLines(sortedEntries["js"])...)
   110  	entryErrs = append(entryErrs, printHTMLLines(sortedEntries["html"])...)
   111  
   112  	if len(entryErrs) == 0 {
   113  		return nil
   114  	}
   115  
   116  	fmt.Printf("\nErrors encountered\n")
   117  	for i := range entryErrs {
   118  		fmt.Println(entryErrs[i])
   119  	}
   120  
   121  	return errors.New("completed with errors")
   122  }
   123  
   124  func printCoreLines(es []*WorksheetEntry) (entryErrs []string) {
   125  	fmt.Printf("\nCore notifications. Put in correct locale map in client/core/locale_ntfn.go\n------------\n")
   126  	noteEntries := make(map[string][2]*WorksheetEntry)
   127  	for _, e := range es {
   128  		var i int
   129  		var entryID string
   130  		switch {
   131  		case strings.HasSuffix(e.ID, " subject"):
   132  			entryID = e.ID[:len(e.ID)-len(" subject")]
   133  		case strings.HasSuffix(e.ID, " template"):
   134  			i = 1
   135  			entryID = e.ID[:len(e.ID)-len(" template")]
   136  		default:
   137  			entryErrs = append(entryErrs, fmt.Sprintf("corrupted ID %q for web notification", e.ID))
   138  			continue
   139  		}
   140  		ne := noteEntries[entryID]
   141  		ne[i] = e
   142  		noteEntries[entryID] = ne
   143  	}
   144  
   145  	var unpaired []*WorksheetEntry
   146  	for entryID, st := range noteEntries {
   147  		subjectEntry, templateEntry := st[0], st[1]
   148  		if subjectEntry == nil {
   149  			if templateEntry == nil {
   150  				entryErrs = append(entryErrs, fmt.Sprintf("Missing subject or template for translation with ID %s", entryID))
   151  			} else {
   152  				unpaired = append(unpaired, templateEntry)
   153  			}
   154  			continue
   155  		} else if templateEntry == nil {
   156  			unpaired = append(unpaired, subjectEntry)
   157  			continue
   158  		}
   159  		fmt.Printf(webNoteTemplate, entryID, formatReportWithType(subjectEntry), formatReportWithType(templateEntry))
   160  	}
   161  	for _, e := range unpaired {
   162  		fmt.Println("Topic"+e.ID, ": ", formatReportWithType(e)+",")
   163  	}
   164  
   165  	return
   166  }
   167  
   168  func printJSLines(es []*WorksheetEntry) (entryErrs []string) {
   169  	fmt.Printf("\nJS Notifications. Add these to the appropriate map in client/webserver/jsintl.go, replacing the IDs with the appropriate variables\n------------\n")
   170  	for _, e := range es {
   171  		fmt.Printf("	%s: %s,\n", e.ID, formatReportEntry(e))
   172  	}
   173  	return
   174  }
   175  
   176  func printHTMLLines(es []*WorksheetEntry) (entryErrs []string) {
   177  	fmt.Printf("\nHTML Notifications. Add these to the language file in client/webserver/locales\n------------\n")
   178  	for _, e := range es {
   179  		fmt.Printf(`	"%s": %s,`+"\n", e.ID, formatReportEntry(e))
   180  	}
   181  	return
   182  }
   183  
   184  func escapeTemplate(s string) string {
   185  	b, _ := json.Marshal(s)
   186  	return string(b)
   187  }
   188  
   189  func formatReportEntry(e *WorksheetEntry) string {
   190  	var v string
   191  	if e.Version > 0 {
   192  		v = fmt.Sprintf("Version: %d, ", e.Version)
   193  	}
   194  	return fmt.Sprintf("{%sT: %s}", v, escapeTemplate(e.Translation))
   195  }
   196  
   197  func formatReportWithType(e *WorksheetEntry) string {
   198  	return fmt.Sprintf("intl.Translation%s", formatReportEntry(e))
   199  }
   200  
   201  var webNoteTemplate = `	Topic%s: {
   202  		subject:  %s,
   203  		template: %s,
   204  	},
   205  `