podman

Форк
0
420 строк · 12.5 Кб
1
package ut
2

3
import (
4
	"fmt"
5
	"strconv"
6
	"strings"
7

8
	"github.com/go-playground/locales"
9
)
10

11
const (
12
	paramZero          = "{0}"
13
	paramOne           = "{1}"
14
	unknownTranslation = ""
15
)
16

17
// Translator is universal translators
18
// translator instance which is a thin wrapper
19
// around locales.Translator instance providing
20
// some extra functionality
21
type Translator interface {
22
	locales.Translator
23

24
	// adds a normal translation for a particular language/locale
25
	// {#} is the only replacement type accepted and are ad infinitum
26
	// eg. one: '{0} day left' other: '{0} days left'
27
	Add(key interface{}, text string, override bool) error
28

29
	// adds a cardinal plural translation for a particular language/locale
30
	// {0} is the only replacement type accepted and only one variable is accepted as
31
	// multiple cannot be used for a plural rule determination, unless it is a range;
32
	// see AddRange below.
33
	// eg. in locale 'en' one: '{0} day left' other: '{0} days left'
34
	AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error
35

36
	// adds an ordinal plural translation for a particular language/locale
37
	// {0} is the only replacement type accepted and only one variable is accepted as
38
	// multiple cannot be used for a plural rule determination, unless it is a range;
39
	// see AddRange below.
40
	// eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring'
41
	// - 1st, 2nd, 3rd...
42
	AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error
43

44
	// adds a range plural translation for a particular language/locale
45
	// {0} and {1} are the only replacement types accepted and only these are accepted.
46
	// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left'
47
	AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error
48

49
	// creates the translation for the locale given the 'key' and params passed in
50
	T(key interface{}, params ...string) (string, error)
51

52
	// creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments
53
	//  and param passed in
54
	C(key interface{}, num float64, digits uint64, param string) (string, error)
55

56
	// creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments
57
	// and param passed in
58
	O(key interface{}, num float64, digits uint64, param string) (string, error)
59

60
	//  creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and
61
	//  'digit2' arguments and 'param1' and 'param2' passed in
62
	R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error)
63

64
	// VerifyTranslations checks to ensures that no plural rules have been
65
	// missed within the translations.
66
	VerifyTranslations() error
67
}
68

69
var _ Translator = new(translator)
70
var _ locales.Translator = new(translator)
71

72
type translator struct {
73
	locales.Translator
74
	translations        map[interface{}]*transText
75
	cardinalTanslations map[interface{}][]*transText // array index is mapped to locales.PluralRule index + the locales.PluralRuleUnknown
76
	ordinalTanslations  map[interface{}][]*transText
77
	rangeTanslations    map[interface{}][]*transText
78
}
79

80
type transText struct {
81
	text    string
82
	indexes []int
83
}
84

85
func newTranslator(trans locales.Translator) Translator {
86
	return &translator{
87
		Translator:          trans,
88
		translations:        make(map[interface{}]*transText), // translation text broken up by byte index
89
		cardinalTanslations: make(map[interface{}][]*transText),
90
		ordinalTanslations:  make(map[interface{}][]*transText),
91
		rangeTanslations:    make(map[interface{}][]*transText),
92
	}
93
}
94

95
// Add adds a normal translation for a particular language/locale
96
// {#} is the only replacement type accepted and are ad infinitum
97
// eg. one: '{0} day left' other: '{0} days left'
98
func (t *translator) Add(key interface{}, text string, override bool) error {
99

100
	if _, ok := t.translations[key]; ok && !override {
101
		return &ErrConflictingTranslation{locale: t.Locale(), key: key, text: text}
102
	}
103

104
	lb := strings.Count(text, "{")
105
	rb := strings.Count(text, "}")
106

107
	if lb != rb {
108
		return &ErrMissingBracket{locale: t.Locale(), key: key, text: text}
109
	}
110

111
	trans := &transText{
112
		text: text,
113
	}
114

115
	var idx int
116

117
	for i := 0; i < lb; i++ {
118
		s := "{" + strconv.Itoa(i) + "}"
119
		idx = strings.Index(text, s)
120
		if idx == -1 {
121
			return &ErrBadParamSyntax{locale: t.Locale(), param: s, key: key, text: text}
122
		}
123

124
		trans.indexes = append(trans.indexes, idx)
125
		trans.indexes = append(trans.indexes, idx+len(s))
126
	}
127

128
	t.translations[key] = trans
129

130
	return nil
131
}
132

133
// AddCardinal adds a cardinal plural translation for a particular language/locale
134
// {0} is the only replacement type accepted and only one variable is accepted as
135
// multiple cannot be used for a plural rule determination, unless it is a range;
136
// see AddRange below.
137
// eg. in locale 'en' one: '{0} day left' other: '{0} days left'
138
func (t *translator) AddCardinal(key interface{}, text string, rule locales.PluralRule, override bool) error {
139

140
	var verified bool
141

142
	// verify plural rule exists for locale
143
	for _, pr := range t.PluralsCardinal() {
144
		if pr == rule {
145
			verified = true
146
			break
147
		}
148
	}
149

150
	if !verified {
151
		return &ErrCardinalTranslation{text: fmt.Sprintf("error: cardinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)}
152
	}
153

154
	tarr, ok := t.cardinalTanslations[key]
155
	if ok {
156
		// verify not adding a conflicting record
157
		if len(tarr) > 0 && tarr[rule] != nil && !override {
158
			return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text}
159
		}
160

161
	} else {
162
		tarr = make([]*transText, 7)
163
		t.cardinalTanslations[key] = tarr
164
	}
165

166
	trans := &transText{
167
		text:    text,
168
		indexes: make([]int, 2),
169
	}
170

171
	tarr[rule] = trans
172

173
	idx := strings.Index(text, paramZero)
174
	if idx == -1 {
175
		tarr[rule] = nil
176
		return &ErrCardinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddCardinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)}
177
	}
178

179
	trans.indexes[0] = idx
180
	trans.indexes[1] = idx + len(paramZero)
181

182
	return nil
183
}
184

185
// AddOrdinal adds an ordinal plural translation for a particular language/locale
186
// {0} is the only replacement type accepted and only one variable is accepted as
187
// multiple cannot be used for a plural rule determination, unless it is a range;
188
// see AddRange below.
189
// eg. in locale 'en' one: '{0}st day of spring' other: '{0}nd day of spring' - 1st, 2nd, 3rd...
190
func (t *translator) AddOrdinal(key interface{}, text string, rule locales.PluralRule, override bool) error {
191

192
	var verified bool
193

194
	// verify plural rule exists for locale
195
	for _, pr := range t.PluralsOrdinal() {
196
		if pr == rule {
197
			verified = true
198
			break
199
		}
200
	}
201

202
	if !verified {
203
		return &ErrOrdinalTranslation{text: fmt.Sprintf("error: ordinal plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)}
204
	}
205

206
	tarr, ok := t.ordinalTanslations[key]
207
	if ok {
208
		// verify not adding a conflicting record
209
		if len(tarr) > 0 && tarr[rule] != nil && !override {
210
			return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text}
211
		}
212

213
	} else {
214
		tarr = make([]*transText, 7)
215
		t.ordinalTanslations[key] = tarr
216
	}
217

218
	trans := &transText{
219
		text:    text,
220
		indexes: make([]int, 2),
221
	}
222

223
	tarr[rule] = trans
224

225
	idx := strings.Index(text, paramZero)
226
	if idx == -1 {
227
		tarr[rule] = nil
228
		return &ErrOrdinalTranslation{text: fmt.Sprintf("error: parameter '%s' not found, may want to use 'Add' instead of 'AddOrdinal'. locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)}
229
	}
230

231
	trans.indexes[0] = idx
232
	trans.indexes[1] = idx + len(paramZero)
233

234
	return nil
235
}
236

237
// AddRange adds a range plural translation for a particular language/locale
238
// {0} and {1} are the only replacement types accepted and only these are accepted.
239
// eg. in locale 'nl' one: '{0}-{1} day left' other: '{0}-{1} days left'
240
func (t *translator) AddRange(key interface{}, text string, rule locales.PluralRule, override bool) error {
241

242
	var verified bool
243

244
	// verify plural rule exists for locale
245
	for _, pr := range t.PluralsRange() {
246
		if pr == rule {
247
			verified = true
248
			break
249
		}
250
	}
251

252
	if !verified {
253
		return &ErrRangeTranslation{text: fmt.Sprintf("error: range plural rule '%s' does not exist for locale '%s' key: '%v' text: '%s'", rule, t.Locale(), key, text)}
254
	}
255

256
	tarr, ok := t.rangeTanslations[key]
257
	if ok {
258
		// verify not adding a conflicting record
259
		if len(tarr) > 0 && tarr[rule] != nil && !override {
260
			return &ErrConflictingTranslation{locale: t.Locale(), key: key, rule: rule, text: text}
261
		}
262

263
	} else {
264
		tarr = make([]*transText, 7)
265
		t.rangeTanslations[key] = tarr
266
	}
267

268
	trans := &transText{
269
		text:    text,
270
		indexes: make([]int, 4),
271
	}
272

273
	tarr[rule] = trans
274

275
	idx := strings.Index(text, paramZero)
276
	if idx == -1 {
277
		tarr[rule] = nil
278
		return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, are you sure you're adding a Range Translation? locale: '%s' key: '%v' text: '%s'", paramZero, t.Locale(), key, text)}
279
	}
280

281
	trans.indexes[0] = idx
282
	trans.indexes[1] = idx + len(paramZero)
283

284
	idx = strings.Index(text, paramOne)
285
	if idx == -1 {
286
		tarr[rule] = nil
287
		return &ErrRangeTranslation{text: fmt.Sprintf("error: parameter '%s' not found, a Range Translation requires two parameters. locale: '%s' key: '%v' text: '%s'", paramOne, t.Locale(), key, text)}
288
	}
289

290
	trans.indexes[2] = idx
291
	trans.indexes[3] = idx + len(paramOne)
292

293
	return nil
294
}
295

296
// T creates the translation for the locale given the 'key' and params passed in
297
func (t *translator) T(key interface{}, params ...string) (string, error) {
298

299
	trans, ok := t.translations[key]
300
	if !ok {
301
		return unknownTranslation, ErrUnknowTranslation
302
	}
303

304
	b := make([]byte, 0, 64)
305

306
	var start, end, count int
307

308
	for i := 0; i < len(trans.indexes); i++ {
309
		end = trans.indexes[i]
310
		b = append(b, trans.text[start:end]...)
311
		b = append(b, params[count]...)
312
		i++
313
		start = trans.indexes[i]
314
		count++
315
	}
316

317
	b = append(b, trans.text[start:]...)
318

319
	return string(b), nil
320
}
321

322
// C creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in
323
func (t *translator) C(key interface{}, num float64, digits uint64, param string) (string, error) {
324

325
	tarr, ok := t.cardinalTanslations[key]
326
	if !ok {
327
		return unknownTranslation, ErrUnknowTranslation
328
	}
329

330
	rule := t.CardinalPluralRule(num, digits)
331

332
	trans := tarr[rule]
333

334
	b := make([]byte, 0, 64)
335
	b = append(b, trans.text[:trans.indexes[0]]...)
336
	b = append(b, param...)
337
	b = append(b, trans.text[trans.indexes[1]:]...)
338

339
	return string(b), nil
340
}
341

342
// O creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in
343
func (t *translator) O(key interface{}, num float64, digits uint64, param string) (string, error) {
344

345
	tarr, ok := t.ordinalTanslations[key]
346
	if !ok {
347
		return unknownTranslation, ErrUnknowTranslation
348
	}
349

350
	rule := t.OrdinalPluralRule(num, digits)
351

352
	trans := tarr[rule]
353

354
	b := make([]byte, 0, 64)
355
	b = append(b, trans.text[:trans.indexes[0]]...)
356
	b = append(b, param...)
357
	b = append(b, trans.text[trans.indexes[1]:]...)
358

359
	return string(b), nil
360
}
361

362
// R creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and 'digit2' arguments
363
// and 'param1' and 'param2' passed in
364
func (t *translator) R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) (string, error) {
365

366
	tarr, ok := t.rangeTanslations[key]
367
	if !ok {
368
		return unknownTranslation, ErrUnknowTranslation
369
	}
370

371
	rule := t.RangePluralRule(num1, digits1, num2, digits2)
372

373
	trans := tarr[rule]
374

375
	b := make([]byte, 0, 64)
376
	b = append(b, trans.text[:trans.indexes[0]]...)
377
	b = append(b, param1...)
378
	b = append(b, trans.text[trans.indexes[1]:trans.indexes[2]]...)
379
	b = append(b, param2...)
380
	b = append(b, trans.text[trans.indexes[3]:]...)
381

382
	return string(b), nil
383
}
384

385
// VerifyTranslations checks to ensures that no plural rules have been
386
// missed within the translations.
387
func (t *translator) VerifyTranslations() error {
388

389
	for k, v := range t.cardinalTanslations {
390

391
		for _, rule := range t.PluralsCardinal() {
392

393
			if v[rule] == nil {
394
				return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "plural", rule: rule, key: k}
395
			}
396
		}
397
	}
398

399
	for k, v := range t.ordinalTanslations {
400

401
		for _, rule := range t.PluralsOrdinal() {
402

403
			if v[rule] == nil {
404
				return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "ordinal", rule: rule, key: k}
405
			}
406
		}
407
	}
408

409
	for k, v := range t.rangeTanslations {
410

411
		for _, rule := range t.PluralsRange() {
412

413
			if v[rule] == nil {
414
				return &ErrMissingPluralTranslation{locale: t.Locale(), translationType: "range", rule: rule, key: k}
415
			}
416
		}
417
	}
418

419
	return nil
420
}
421

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.