Skip to content

Commit d48facf

Browse files
committed
feat: add trans_choice() method.
1 parent 3632f9e commit d48facf

File tree

5 files changed

+481
-3
lines changed

5 files changed

+481
-3
lines changed

src/index.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { reactive, Plugin } from 'vue'
22
import { OptionsInterface } from './interfaces/options'
33
import { LanguageInterface } from './interfaces/language'
44
import { ReplacementsInterface } from './interfaces/replacements'
5+
import { choose } from './pluralization'
56

67
/**
78
* The Default language will be used if there is no lang provided.
@@ -70,13 +71,29 @@ export function loadLanguageAsync(lang: string): Promise<string | void> {
7071
/**
7172
* Get the translation for the given key.
7273
*/
73-
export function trans(key: string, replacements?: ReplacementsInterface): string {
74+
export function trans(key: string, replacements: ReplacementsInterface = {}): string {
7475
if (!activeMessages[key]) {
7576
activeMessages[key] = key
7677
}
7778

78-
let message = activeMessages[key]
79+
return makeReplacements(activeMessages[key], replacements)
80+
}
81+
82+
/**
83+
* Translates the given message based on a count.
84+
*/
85+
export function trans_choice(key: string, number: number, replacements: ReplacementsInterface = {}): string {
86+
const message = trans(key, replacements)
87+
88+
replacements.count = number.toString()
7989

90+
return makeReplacements(choose(message, number, options.lang), replacements)
91+
}
92+
93+
/**
94+
* Make the place-holder replacements on a line.
95+
*/
96+
function makeReplacements(message: string, replacements?: ReplacementsInterface): string {
8097
const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1)
8198

8299
Object.entries(replacements || []).forEach(([key, value]) => {

src/pluralization.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { getPluralIndex } from './utils/get-plural-index'
2+
3+
/**
4+
* Select a proper translation string based on the given number.
5+
*/
6+
export function choose(message: string, number: number, lang: string): string {
7+
let segments = message.split('|')
8+
const extracted = extract(segments, number)
9+
10+
if (extracted !== null) {
11+
return extracted.trim()
12+
}
13+
14+
segments = stripConditions(segments)
15+
const pluralIndex = getPluralIndex(lang, number)
16+
17+
if (segments.length === 1 || !segments[pluralIndex]) {
18+
return segments[0]
19+
}
20+
21+
return segments[pluralIndex]
22+
}
23+
24+
/**
25+
* Extract a translation string using inline conditions.
26+
*/
27+
function extract(segments: string[], number: number): string | null {
28+
for (const part of segments) {
29+
let line = extractFromString(part, number)
30+
31+
if (line !== null) {
32+
return line
33+
}
34+
}
35+
36+
return null
37+
}
38+
39+
/**
40+
* Get the translation string if the condition matches.
41+
*/
42+
function extractFromString(part: string, number: number): string | null {
43+
const matches = part.match(/^[\{\[]([^\[\]\{\}]*)[\}\]](.*)/s) || []
44+
if (matches.length !== 3) {
45+
return null
46+
}
47+
48+
const condition = matches[1]
49+
const value = matches[2]
50+
51+
if (condition.includes(',')) {
52+
let [from, to] = condition.split(',')
53+
54+
if (to === '*' && number >= parseFloat(from)) {
55+
return value
56+
} else if (from === '*' && number <= parseFloat(to)) {
57+
return value
58+
} else if (number >= parseFloat(from) && number <= parseFloat(to)) {
59+
return value
60+
}
61+
}
62+
63+
return parseFloat(condition) === number ? value : null
64+
}
65+
66+
/**
67+
* Strip the inline conditions from each segment, just leaving the text.
68+
*/
69+
function stripConditions(segments: string[]): string[] {
70+
return segments.map((part) => part.replace(/^[\{\[]([^\[\]\{\}]*)[\}\]]/, ''))
71+
}

0 commit comments

Comments
 (0)