golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/l18n/l18n.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package l18n
     7  
     8  import (
     9  	"sync"
    10  
    11  	"golang.org/x/sys/windows"
    12  	"golang.org/x/text/language"
    13  	"golang.org/x/text/message"
    14  )
    15  
    16  var (
    17  	printer     *message.Printer
    18  	printerLock sync.Mutex
    19  )
    20  
    21  // prn returns the printer for user preferred UI language.
    22  func prn() *message.Printer {
    23  	if printer != nil {
    24  		return printer
    25  	}
    26  	printerLock.Lock()
    27  	if printer != nil {
    28  		printerLock.Unlock()
    29  		return printer
    30  	}
    31  	printer = message.NewPrinter(lang())
    32  	printerLock.Unlock()
    33  	return printer
    34  }
    35  
    36  // lang returns the user preferred UI language we have most confident translation in the default catalog available.
    37  func lang() (tag language.Tag) {
    38  	tag = language.English
    39  	confidence := language.No
    40  	languages, err := windows.GetUserPreferredUILanguages(windows.MUI_LANGUAGE_NAME)
    41  	if err != nil {
    42  		return
    43  	}
    44  	for i := range languages {
    45  		t, _, c := message.DefaultCatalog.Matcher().Match(message.MatchLanguage(languages[i]))
    46  		if c > confidence {
    47  			tag = t
    48  			confidence = c
    49  		}
    50  	}
    51  	return
    52  }
    53  
    54  // Sprintf is like fmt.Sprintf, but using language-specific formatting.
    55  func Sprintf(key message.Reference, a ...any) string {
    56  	return prn().Sprintf(key, a...)
    57  }
    58  
    59  // EnumerationSeparator returns enumeration separator. For English and western languages,
    60  // enumeration separator is a comma followed by a space (i.e. ", "). For Chinese, it returns
    61  // "\u3001".
    62  func EnumerationSeparator() string {
    63  	// BUG: We could just use `Sprintf(", " /* ...translator instructions... */)` and let the
    64  	// individual locale catalog handle its translation. Unfortunately, the gotext utility tries to
    65  	// be nice to translators and skips all strings without letters when updating catalogs.
    66  	return Sprintf("[EnumerationSeparator]" /* Text to insert between items when listing - most western languages will translate ‘[EnumerationSeparator]’ into ‘, ’ to produce lists like ‘apple, orange, strawberry’. Eastern languages might translate into ‘、’ to produce lists like ‘リンゴ、オレンジ、イチゴ’. */)
    67  }
    68  
    69  // UnitSeparator returns the separator to use when concatenating multiple units of the same metric
    70  // (e.g. "1 minute, 32 seconds", "6 feet, 1 inch"). For English and western languages, unit
    71  // separator is a comma followed by a space (i.e. ", "). For Slovenian and Japanese, it returns
    72  // just space.
    73  func UnitSeparator() string {
    74  	// BUG: We could just use `Sprintf(", " /* ...translator instructions... */)` and let the
    75  	// individual locale catalog handle its translation. Unfortunately, the gotext utility tries to
    76  	// be nice to translators and skips all strings without letters when updating catalogs.
    77  	return Sprintf("[UnitSeparator]" /* Text to insert when combining units of a measure - most languages will translate ‘[UnitSeparator]’ into ‘ ’ (space) to produce lists like ‘2 minuti 30 sekund’, or empty string ‘’ to produce ‘2分30秒’. */)
    78  }