@jarenjs/locales 0.46.4 → 0.49.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -4
- package/dist/types/dates.d.ts +68 -0
- package/dist/types/helpers.d.ts +63 -2
- package/dist/types/index.d.ts +11 -0
- package/dist/types/intl-dates.d.ts +20 -0
- package/package.json +10 -2
- package/src/ar.js +76 -1
- package/src/dates.js +263 -0
- package/src/de.js +49 -0
- package/src/es.js +47 -0
- package/src/fr.js +49 -0
- package/src/helpers.js +116 -2
- package/src/index.js +12 -0
- package/src/intl-dates.js +160 -0
- package/src/ja.js +49 -0
- package/src/ko.js +49 -0
- package/src/nl.js +49 -0
- package/src/pt.js +47 -0
- package/src/ru.js +63 -4
- package/src/tr.js +49 -0
- package/src/zh-tw.js +49 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The opt-in `Intl` calendar language: the same compiled shape
|
|
5
|
+
* `compileDateLocale` returns, sourced from the platform's ICU data
|
|
6
|
+
* instead of from this repository.
|
|
7
|
+
*
|
|
8
|
+
* It is a separate module and an explicit call because it is the one
|
|
9
|
+
* thing the default may not be. ICU output moves between Node versions
|
|
10
|
+
* and between a browser and a server, so a page rendered from it cannot
|
|
11
|
+
* be compared byte for byte - which is exactly what this site's
|
|
12
|
+
* server-rendering tests do. What it buys instead is every locale the
|
|
13
|
+
* host ships rather than the eleven this repository owns, so a host that
|
|
14
|
+
* needs breadth more than byte stability constructs one and passes it
|
|
15
|
+
* where a `compileDateLocale` result would go.
|
|
16
|
+
*
|
|
17
|
+
* Nothing here runs at module load: the `Intl` objects are built inside
|
|
18
|
+
* the factory, so importing the module allocates nothing and a bundle
|
|
19
|
+
* that never calls it carries no ICU work.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { checkRelativeArguments } from './helpers.js';
|
|
23
|
+
|
|
24
|
+
import { dateMessagesEn } from './dates.js';
|
|
25
|
+
|
|
26
|
+
/** 1970-01-04 was a Sunday: the weekday index every name array starts at. */
|
|
27
|
+
const FIRST_SUNDAY = Date.UTC(1970, 0, 4);
|
|
28
|
+
|
|
29
|
+
/** A reference year; the 15th keeps every month clear of a leap edge. */
|
|
30
|
+
const REFERENCE_YEAR = 2021;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Read the display names this repository owns, keyed by format name.
|
|
34
|
+
* ICU has no equivalent data - a format name is a JSON Schema fact, not
|
|
35
|
+
* a calendar one - so the `Intl` provider carries the English ones and
|
|
36
|
+
* takes an override.
|
|
37
|
+
* @returns {Record<string, string>}
|
|
38
|
+
*/
|
|
39
|
+
function englishFormatNames() {
|
|
40
|
+
/** @type {Record<string, string>} */
|
|
41
|
+
const names = {};
|
|
42
|
+
for (const key of Object.keys(dateMessagesEn)) {
|
|
43
|
+
if (key.startsWith('format/name/'))
|
|
44
|
+
names[key.slice('format/name/'.length)] = /** @type {string} */ (dateMessagesEn[key]);
|
|
45
|
+
}
|
|
46
|
+
return names;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Read one array of names out of an `Intl.DateTimeFormat`. The calendar
|
|
51
|
+
* is pinned to `gregory` because this suite's dates are proleptic
|
|
52
|
+
* Gregorian; a locale whose default calendar is another one would
|
|
53
|
+
* otherwise name months that no `yyyy-MM-dd` value has.
|
|
54
|
+
* @param {string} locale - The BCP 47 locale tag
|
|
55
|
+
* @param {Intl.DateTimeFormatOptions} options - The name width to read
|
|
56
|
+
* @param {number[]} instants - One reference instant per name
|
|
57
|
+
* @returns {string[]}
|
|
58
|
+
*/
|
|
59
|
+
function namesFrom(locale, options, instants) {
|
|
60
|
+
const format = new Intl.DateTimeFormat(locale, {
|
|
61
|
+
...options,
|
|
62
|
+
calendar: 'gregory',
|
|
63
|
+
timeZone: 'UTC',
|
|
64
|
+
});
|
|
65
|
+
return instants.map((at) => format.format(at));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Read the two day-period markers. `formatToParts` rather than `format`:
|
|
70
|
+
* the marker is one part of a formatted hour, and slicing it out of the
|
|
71
|
+
* whole string would depend on where the locale puts it.
|
|
72
|
+
* @param {string} locale - The BCP 47 locale tag
|
|
73
|
+
* @returns {string[]} The AM and PM markers
|
|
74
|
+
*/
|
|
75
|
+
function meridiemFrom(locale) {
|
|
76
|
+
const format = new Intl.DateTimeFormat(locale, {
|
|
77
|
+
hour: 'numeric',
|
|
78
|
+
hour12: true,
|
|
79
|
+
calendar: 'gregory',
|
|
80
|
+
timeZone: 'UTC',
|
|
81
|
+
});
|
|
82
|
+
const read = (hour) => {
|
|
83
|
+
const part = format.formatToParts(Date.UTC(REFERENCE_YEAR, 0, 1, hour))
|
|
84
|
+
.find((p) => p.type === 'dayPeriod');
|
|
85
|
+
return part === undefined ? '' : part.value;
|
|
86
|
+
};
|
|
87
|
+
const am = read(6);
|
|
88
|
+
const pm = read(18);
|
|
89
|
+
// a locale the host renders on a 24-hour clock has no marker to read;
|
|
90
|
+
// the two tokens still have to render something a pattern can print
|
|
91
|
+
return [am === '' ? 'AM' : am, pm === '' ? 'PM' : pm];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Build a calendar language from the host's ICU data.
|
|
96
|
+
*
|
|
97
|
+
* The returned shape is the one `compileDateLocale` returns, so a
|
|
98
|
+
* consumer takes either without knowing which: `names` plugs into
|
|
99
|
+
* `compileDateFormat`, and `relative` takes the same signed amount and
|
|
100
|
+
* refuses the same arguments. What differs is only where the text comes
|
|
101
|
+
* from, and therefore whether it is stable across host versions.
|
|
102
|
+
*
|
|
103
|
+
* @param {string} locale - A BCP 47 locale tag (`'nl-NL'`)
|
|
104
|
+
* @param {{formatNames?: Record<string, string>}} [options] - Date-format display names, merged over the English ones
|
|
105
|
+
* @returns {Readonly<import('./dates.js').DateLocale>} The frozen calendar language
|
|
106
|
+
* @example
|
|
107
|
+
* const dates = createIntlDateLocale('hu-HU');
|
|
108
|
+
* compileDateFormat('yyyy MMMM d.', dates.names);
|
|
109
|
+
* dates.relative(-3, 'day'); // '3 napja'
|
|
110
|
+
*/
|
|
111
|
+
export function createIntlDateLocale(locale, options = undefined) {
|
|
112
|
+
const monthInstants = [];
|
|
113
|
+
for (let m = 0; m < 12; ++m) monthInstants.push(Date.UTC(REFERENCE_YEAR, m, 15));
|
|
114
|
+
const weekdayInstants = [];
|
|
115
|
+
for (let d = 0; d < 7; ++d) weekdayInstants.push(FIRST_SUNDAY + d * 86400000);
|
|
116
|
+
|
|
117
|
+
const names = Object.freeze({
|
|
118
|
+
months: Object.freeze(namesFrom(locale, { month: 'long' }, monthInstants)),
|
|
119
|
+
monthsShort: Object.freeze(namesFrom(locale, { month: 'short' }, monthInstants)),
|
|
120
|
+
weekdays: Object.freeze(namesFrom(locale, { weekday: 'long' }, weekdayInstants)),
|
|
121
|
+
weekdaysShort: Object.freeze(namesFrom(locale, { weekday: 'short' }, weekdayInstants)),
|
|
122
|
+
meridiem: /** @type {[string, string]} */ (/** @type {unknown} */ (
|
|
123
|
+
Object.freeze(meridiemFrom(locale)))),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// one formatter per numeric mode, built here rather than per phrase
|
|
127
|
+
const always = new Intl.RelativeTimeFormat(locale, { numeric: 'always' });
|
|
128
|
+
const auto = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
|
|
129
|
+
|
|
130
|
+
const formatNames = { ...englishFormatNames(), ...(options?.formatNames) };
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Phrase a signed offset through `Intl.RelativeTimeFormat`.
|
|
134
|
+
* @param {number} amount - Whole units, signed
|
|
135
|
+
* @param {string} unit - One of second|minute|hour|day|week|month|year
|
|
136
|
+
* @param {{numeric?: string}} [callOptions] - `numeric: 'auto'` prefers the named days
|
|
137
|
+
* @returns {string}
|
|
138
|
+
*/
|
|
139
|
+
function relative(amount, unit, callOptions = undefined) {
|
|
140
|
+
const numeric = checkRelativeArguments(amount, unit, callOptions);
|
|
141
|
+
const format = numeric === 'auto' ? auto : always;
|
|
142
|
+
// a signed zero is a direction ICU would render, and this contract
|
|
143
|
+
// has only the one zero
|
|
144
|
+
const signed = Object.is(amount, -0) ? 0 : amount;
|
|
145
|
+
return format.format(signed, /** @type {Intl.RelativeTimeFormatUnit} */ (unit));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The display name of a date/time format.
|
|
150
|
+
* @param {string} format - A format name (`'date-time'`)
|
|
151
|
+
* @returns {string|undefined}
|
|
152
|
+
*/
|
|
153
|
+
function formatName(format) {
|
|
154
|
+
return typeof format === 'string' && Object.hasOwn(formatNames, format)
|
|
155
|
+
? formatNames[format]
|
|
156
|
+
: undefined;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return Object.freeze({ names, relative, formatName });
|
|
160
|
+
}
|
package/src/ja.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
formatMessageValue,
|
|
24
24
|
makeNumberRenderer,
|
|
25
25
|
makeTypeNamer,
|
|
26
|
+
dateNameEntries,
|
|
26
27
|
} from './helpers.js';
|
|
27
28
|
|
|
28
29
|
//#region Intl singletons
|
|
@@ -162,4 +163,52 @@ export const ja = {
|
|
|
162
163
|
'contract/stream-error': '操作 {op} のストリームはサーバーエラーで終了しました ({code})',
|
|
163
164
|
'contract/heartbeat-missed': '操作 {op} のストリームが {ms} ミリ秒間沈黙しました',
|
|
164
165
|
//#endregion
|
|
166
|
+
|
|
167
|
+
//#region calendar language (the date names, relative phrasing and
|
|
168
|
+
// format display names of @jarenjs/locales' date adapter)
|
|
169
|
+
// Japanese counts through counters and has no plural, so the wide and
|
|
170
|
+
// abbreviated month names are the same string - as CLDR has them.
|
|
171
|
+
...dateNameEntries({
|
|
172
|
+
months: [
|
|
173
|
+
'1月', '2月', '3月', '4月', '5月', '6月',
|
|
174
|
+
'7月', '8月', '9月', '10月', '11月', '12月',
|
|
175
|
+
],
|
|
176
|
+
monthsShort: [
|
|
177
|
+
'1月', '2月', '3月', '4月', '5月', '6月',
|
|
178
|
+
'7月', '8月', '9月', '10月', '11月', '12月',
|
|
179
|
+
],
|
|
180
|
+
weekdays: [
|
|
181
|
+
'日曜日', '月曜日', '火曜日', '水曜日',
|
|
182
|
+
'木曜日', '金曜日', '土曜日',
|
|
183
|
+
],
|
|
184
|
+
weekdaysShort: [
|
|
185
|
+
'日', '月', '火', '水', '木', '金', '土',
|
|
186
|
+
],
|
|
187
|
+
meridiem: ['午前', '午後'],
|
|
188
|
+
}),
|
|
189
|
+
'date/relative/second/past': (p) => `${num(p.value)} 秒前`,
|
|
190
|
+
'date/relative/second/future': (p) => `${num(p.value)} 秒後`,
|
|
191
|
+
'date/relative/minute/past': (p) => `${num(p.value)} 分前`,
|
|
192
|
+
'date/relative/minute/future': (p) => `${num(p.value)} 分後`,
|
|
193
|
+
'date/relative/hour/past': (p) => `${num(p.value)} 時間前`,
|
|
194
|
+
'date/relative/hour/future': (p) => `${num(p.value)} 時間後`,
|
|
195
|
+
'date/relative/day/past': (p) => `${num(p.value)} 日前`,
|
|
196
|
+
'date/relative/day/future': (p) => `${num(p.value)} 日後`,
|
|
197
|
+
'date/relative/week/past': (p) => `${num(p.value)} 週間前`,
|
|
198
|
+
'date/relative/week/future': (p) => `${num(p.value)} 週間後`,
|
|
199
|
+
'date/relative/month/past': (p) => `${num(p.value)} か月前`,
|
|
200
|
+
'date/relative/month/future': (p) => `${num(p.value)} か月後`,
|
|
201
|
+
'date/relative/year/past': (p) => `${num(p.value)} 年前`,
|
|
202
|
+
'date/relative/year/future': (p) => `${num(p.value)} 年後`,
|
|
203
|
+
'date/relative/now': '今',
|
|
204
|
+
'date/relative/yesterday': '昨日',
|
|
205
|
+
'date/relative/today': '今日',
|
|
206
|
+
'date/relative/tomorrow': '明日',
|
|
207
|
+
'format/name/date': '日付',
|
|
208
|
+
'format/name/time': '時刻',
|
|
209
|
+
'format/name/date-time': '日時',
|
|
210
|
+
'format/name/iso-date': 'ISO 日付',
|
|
211
|
+
'format/name/iso-time': 'ISO 時刻',
|
|
212
|
+
'format/name/iso-date-time': 'ISO 日時',
|
|
213
|
+
//#endregion
|
|
165
214
|
};
|
package/src/ko.js
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
formatMessageValue,
|
|
27
27
|
makeNumberRenderer,
|
|
28
28
|
makeTypeNamer,
|
|
29
|
+
dateNameEntries,
|
|
29
30
|
} from './helpers.js';
|
|
30
31
|
|
|
31
32
|
//#region Intl singletons
|
|
@@ -165,4 +166,52 @@ export const ko = {
|
|
|
165
166
|
'contract/stream-error': '작업 {op}의 스트림이 서버 오류로 종료되었습니다 ({code})',
|
|
166
167
|
'contract/heartbeat-missed': '작업 {op}의 스트림이 {ms}ms 동안 침묵했습니다',
|
|
167
168
|
//#endregion
|
|
169
|
+
|
|
170
|
+
//#region calendar language (the date names, relative phrasing and
|
|
171
|
+
// format display names of @jarenjs/locales' date adapter)
|
|
172
|
+
// Korean has no plural and sets no space between a numeral and its
|
|
173
|
+
// counter, the way the rest of this pack already counts characters.
|
|
174
|
+
...dateNameEntries({
|
|
175
|
+
months: [
|
|
176
|
+
'1월', '2월', '3월', '4월', '5월', '6월',
|
|
177
|
+
'7월', '8월', '9월', '10월', '11월', '12월',
|
|
178
|
+
],
|
|
179
|
+
monthsShort: [
|
|
180
|
+
'1월', '2월', '3월', '4월', '5월', '6월',
|
|
181
|
+
'7월', '8월', '9월', '10월', '11월', '12월',
|
|
182
|
+
],
|
|
183
|
+
weekdays: [
|
|
184
|
+
'일요일', '월요일', '화요일', '수요일',
|
|
185
|
+
'목요일', '금요일', '토요일',
|
|
186
|
+
],
|
|
187
|
+
weekdaysShort: [
|
|
188
|
+
'일', '월', '화', '수', '목', '금', '토',
|
|
189
|
+
],
|
|
190
|
+
meridiem: ['오전', '오후'],
|
|
191
|
+
}),
|
|
192
|
+
'date/relative/second/past': (p) => `${num(p.value)}초 전`,
|
|
193
|
+
'date/relative/second/future': (p) => `${num(p.value)}초 후`,
|
|
194
|
+
'date/relative/minute/past': (p) => `${num(p.value)}분 전`,
|
|
195
|
+
'date/relative/minute/future': (p) => `${num(p.value)}분 후`,
|
|
196
|
+
'date/relative/hour/past': (p) => `${num(p.value)}시간 전`,
|
|
197
|
+
'date/relative/hour/future': (p) => `${num(p.value)}시간 후`,
|
|
198
|
+
'date/relative/day/past': (p) => `${num(p.value)}일 전`,
|
|
199
|
+
'date/relative/day/future': (p) => `${num(p.value)}일 후`,
|
|
200
|
+
'date/relative/week/past': (p) => `${num(p.value)}주 전`,
|
|
201
|
+
'date/relative/week/future': (p) => `${num(p.value)}주 후`,
|
|
202
|
+
'date/relative/month/past': (p) => `${num(p.value)}개월 전`,
|
|
203
|
+
'date/relative/month/future': (p) => `${num(p.value)}개월 후`,
|
|
204
|
+
'date/relative/year/past': (p) => `${num(p.value)}년 전`,
|
|
205
|
+
'date/relative/year/future': (p) => `${num(p.value)}년 후`,
|
|
206
|
+
'date/relative/now': '지금',
|
|
207
|
+
'date/relative/yesterday': '어제',
|
|
208
|
+
'date/relative/today': '오늘',
|
|
209
|
+
'date/relative/tomorrow': '내일',
|
|
210
|
+
'format/name/date': '날짜',
|
|
211
|
+
'format/name/time': '시간',
|
|
212
|
+
'format/name/date-time': '날짜 및 시간',
|
|
213
|
+
'format/name/iso-date': 'ISO 날짜',
|
|
214
|
+
'format/name/iso-time': 'ISO 시간',
|
|
215
|
+
'format/name/iso-date-time': 'ISO 날짜 및 시간',
|
|
216
|
+
//#endregion
|
|
168
217
|
};
|
package/src/nl.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
makeNumberRenderer,
|
|
24
24
|
makePluralPicker,
|
|
25
25
|
makeTypeNamer,
|
|
26
|
+
dateNameEntries,
|
|
26
27
|
} from './helpers.js';
|
|
27
28
|
|
|
28
29
|
//#region Intl singletons
|
|
@@ -166,4 +167,52 @@ export const nl = {
|
|
|
166
167
|
'contract/stream-error': 'de stream van operatie {op} is geëindigd met een serverfout ({code})',
|
|
167
168
|
'contract/heartbeat-missed': 'de stream van operatie {op} is {ms} ms stil gebleven',
|
|
168
169
|
//#endregion
|
|
170
|
+
|
|
171
|
+
//#region calendar language (the date names, relative phrasing and
|
|
172
|
+
// format display names of @jarenjs/locales' date adapter)
|
|
173
|
+
// 'uur' and 'jaar' do not take a plural after a numeral, so those two
|
|
174
|
+
// units repeat the same noun rather than pretending to agree.
|
|
175
|
+
...dateNameEntries({
|
|
176
|
+
months: [
|
|
177
|
+
'januari', 'februari', 'maart', 'april', 'mei', 'juni',
|
|
178
|
+
'juli', 'augustus', 'september', 'oktober', 'november', 'december',
|
|
179
|
+
],
|
|
180
|
+
monthsShort: [
|
|
181
|
+
'jan', 'feb', 'mrt', 'apr', 'mei', 'jun',
|
|
182
|
+
'jul', 'aug', 'sep', 'okt', 'nov', 'dec',
|
|
183
|
+
],
|
|
184
|
+
weekdays: [
|
|
185
|
+
'zondag', 'maandag', 'dinsdag', 'woensdag',
|
|
186
|
+
'donderdag', 'vrijdag', 'zaterdag',
|
|
187
|
+
],
|
|
188
|
+
weekdaysShort: [
|
|
189
|
+
'zo', 'ma', 'di', 'wo', 'do', 'vr', 'za',
|
|
190
|
+
],
|
|
191
|
+
meridiem: ['a.m.', 'p.m.'],
|
|
192
|
+
}),
|
|
193
|
+
'date/relative/second/past': (p) => `${num(p.value)} ${plural(p.value, 'seconde', 'seconden')} geleden`,
|
|
194
|
+
'date/relative/second/future': (p) => `over ${num(p.value)} ${plural(p.value, 'seconde', 'seconden')}`,
|
|
195
|
+
'date/relative/minute/past': (p) => `${num(p.value)} ${plural(p.value, 'minuut', 'minuten')} geleden`,
|
|
196
|
+
'date/relative/minute/future': (p) => `over ${num(p.value)} ${plural(p.value, 'minuut', 'minuten')}`,
|
|
197
|
+
'date/relative/hour/past': (p) => `${num(p.value)} ${plural(p.value, 'uur', 'uur')} geleden`,
|
|
198
|
+
'date/relative/hour/future': (p) => `over ${num(p.value)} ${plural(p.value, 'uur', 'uur')}`,
|
|
199
|
+
'date/relative/day/past': (p) => `${num(p.value)} ${plural(p.value, 'dag', 'dagen')} geleden`,
|
|
200
|
+
'date/relative/day/future': (p) => `over ${num(p.value)} ${plural(p.value, 'dag', 'dagen')}`,
|
|
201
|
+
'date/relative/week/past': (p) => `${num(p.value)} ${plural(p.value, 'week', 'weken')} geleden`,
|
|
202
|
+
'date/relative/week/future': (p) => `over ${num(p.value)} ${plural(p.value, 'week', 'weken')}`,
|
|
203
|
+
'date/relative/month/past': (p) => `${num(p.value)} ${plural(p.value, 'maand', 'maanden')} geleden`,
|
|
204
|
+
'date/relative/month/future': (p) => `over ${num(p.value)} ${plural(p.value, 'maand', 'maanden')}`,
|
|
205
|
+
'date/relative/year/past': (p) => `${num(p.value)} ${plural(p.value, 'jaar', 'jaar')} geleden`,
|
|
206
|
+
'date/relative/year/future': (p) => `over ${num(p.value)} ${plural(p.value, 'jaar', 'jaar')}`,
|
|
207
|
+
'date/relative/now': 'nu',
|
|
208
|
+
'date/relative/yesterday': 'gisteren',
|
|
209
|
+
'date/relative/today': 'vandaag',
|
|
210
|
+
'date/relative/tomorrow': 'morgen',
|
|
211
|
+
'format/name/date': 'datum',
|
|
212
|
+
'format/name/time': 'tijd',
|
|
213
|
+
'format/name/date-time': 'datum en tijd',
|
|
214
|
+
'format/name/iso-date': 'ISO-datum',
|
|
215
|
+
'format/name/iso-time': 'ISO-tijd',
|
|
216
|
+
'format/name/iso-date-time': 'ISO-datum en -tijd',
|
|
217
|
+
//#endregion
|
|
169
218
|
};
|
package/src/pt.js
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
makeNumberRenderer,
|
|
25
25
|
makePluralPicker,
|
|
26
26
|
makeTypeNamer,
|
|
27
|
+
dateNameEntries,
|
|
27
28
|
} from './helpers.js';
|
|
28
29
|
|
|
29
30
|
//#region Intl singletons
|
|
@@ -167,4 +168,50 @@ export const pt = {
|
|
|
167
168
|
'contract/stream-error': 'o fluxo da operação {op} terminou com um erro do servidor ({code})',
|
|
168
169
|
'contract/heartbeat-missed': 'o fluxo da operação {op} ficou em silêncio por {ms} ms',
|
|
169
170
|
//#endregion
|
|
171
|
+
|
|
172
|
+
//#region calendar language (the date names, relative phrasing and
|
|
173
|
+
// format display names of @jarenjs/locales' date adapter)
|
|
174
|
+
...dateNameEntries({
|
|
175
|
+
months: [
|
|
176
|
+
'janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho',
|
|
177
|
+
'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro',
|
|
178
|
+
],
|
|
179
|
+
monthsShort: [
|
|
180
|
+
'jan.', 'fev.', 'mar.', 'abr.', 'mai.', 'jun.',
|
|
181
|
+
'jul.', 'ago.', 'set.', 'out.', 'nov.', 'dez.',
|
|
182
|
+
],
|
|
183
|
+
weekdays: [
|
|
184
|
+
'domingo', 'segunda-feira', 'terça-feira', 'quarta-feira',
|
|
185
|
+
'quinta-feira', 'sexta-feira', 'sábado',
|
|
186
|
+
],
|
|
187
|
+
weekdaysShort: [
|
|
188
|
+
'dom.', 'seg.', 'ter.', 'qua.', 'qui.', 'sex.', 'sáb.',
|
|
189
|
+
],
|
|
190
|
+
meridiem: ['a.m.', 'p.m.'],
|
|
191
|
+
}),
|
|
192
|
+
'date/relative/second/past': (p) => `há ${num(p.value)} ${plural(p.value, 'segundo', 'segundos')}`,
|
|
193
|
+
'date/relative/second/future': (p) => `dentro de ${num(p.value)} ${plural(p.value, 'segundo', 'segundos')}`,
|
|
194
|
+
'date/relative/minute/past': (p) => `há ${num(p.value)} ${plural(p.value, 'minuto', 'minutos')}`,
|
|
195
|
+
'date/relative/minute/future': (p) => `dentro de ${num(p.value)} ${plural(p.value, 'minuto', 'minutos')}`,
|
|
196
|
+
'date/relative/hour/past': (p) => `há ${num(p.value)} ${plural(p.value, 'hora', 'horas')}`,
|
|
197
|
+
'date/relative/hour/future': (p) => `dentro de ${num(p.value)} ${plural(p.value, 'hora', 'horas')}`,
|
|
198
|
+
'date/relative/day/past': (p) => `há ${num(p.value)} ${plural(p.value, 'dia', 'dias')}`,
|
|
199
|
+
'date/relative/day/future': (p) => `dentro de ${num(p.value)} ${plural(p.value, 'dia', 'dias')}`,
|
|
200
|
+
'date/relative/week/past': (p) => `há ${num(p.value)} ${plural(p.value, 'semana', 'semanas')}`,
|
|
201
|
+
'date/relative/week/future': (p) => `dentro de ${num(p.value)} ${plural(p.value, 'semana', 'semanas')}`,
|
|
202
|
+
'date/relative/month/past': (p) => `há ${num(p.value)} ${plural(p.value, 'mês', 'meses')}`,
|
|
203
|
+
'date/relative/month/future': (p) => `dentro de ${num(p.value)} ${plural(p.value, 'mês', 'meses')}`,
|
|
204
|
+
'date/relative/year/past': (p) => `há ${num(p.value)} ${plural(p.value, 'ano', 'anos')}`,
|
|
205
|
+
'date/relative/year/future': (p) => `dentro de ${num(p.value)} ${plural(p.value, 'ano', 'anos')}`,
|
|
206
|
+
'date/relative/now': 'agora',
|
|
207
|
+
'date/relative/yesterday': 'ontem',
|
|
208
|
+
'date/relative/today': 'hoje',
|
|
209
|
+
'date/relative/tomorrow': 'amanhã',
|
|
210
|
+
'format/name/date': 'data',
|
|
211
|
+
'format/name/time': 'hora',
|
|
212
|
+
'format/name/date-time': 'data e hora',
|
|
213
|
+
'format/name/iso-date': 'data ISO',
|
|
214
|
+
'format/name/iso-time': 'hora ISO',
|
|
215
|
+
'format/name/iso-date-time': 'data e hora ISO',
|
|
216
|
+
//#endregion
|
|
170
217
|
};
|
package/src/ru.js
CHANGED
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
* Globalization mechanics (the pack-authoring pattern - see
|
|
14
14
|
* packages/validate/docs/ERROR-MESSAGES.md):
|
|
15
15
|
* - `Intl.PluralRules` picks plural categories. Russian counts split
|
|
16
|
-
* one/few/many
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* one/few/many; every counted noun following "менее/более" reads in
|
|
17
|
+
* the genitive, where only the 'one' category differs ("21 символа" /
|
|
18
|
+
* "22 символов") and a two-form helper suffices, while the
|
|
19
|
+
* relative-time nouns take the accusative and need all three,
|
|
20
20
|
* - `Intl.NumberFormat` renders numeric limits the Russian way,
|
|
21
21
|
* - `Intl.ListFormat` renders enum alternatives ("a, b или c"),
|
|
22
22
|
* all held as module-level singletons (allocation discipline).
|
|
@@ -25,8 +25,10 @@
|
|
|
25
25
|
import {
|
|
26
26
|
formatMessageValue,
|
|
27
27
|
makeNumberRenderer,
|
|
28
|
+
makePluralForms,
|
|
28
29
|
makePluralPicker,
|
|
29
30
|
makeTypeNamer,
|
|
31
|
+
dateNameEntries,
|
|
30
32
|
} from './helpers.js';
|
|
31
33
|
|
|
32
34
|
//#region Intl singletons
|
|
@@ -42,6 +44,13 @@ const listFormat = new Intl.ListFormat('ru', { style: 'long', type: 'disjunction
|
|
|
42
44
|
*/
|
|
43
45
|
const plural = makePluralPicker(pluralRules);
|
|
44
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Pick the accusative form a counted relative-time noun takes: 'one'
|
|
49
|
+
* recurs at 21, 31 ... and 'few' at 22-24, so the three forms follow the
|
|
50
|
+
* CLDR category rather than the number's last digit.
|
|
51
|
+
*/
|
|
52
|
+
const caseForms = makePluralForms(pluralRules);
|
|
53
|
+
|
|
45
54
|
/**
|
|
46
55
|
* Render a numeric limit through the Russian number format; non-numbers
|
|
47
56
|
* (e.g. an unresolved $data pointer) render as-is.
|
|
@@ -177,4 +186,54 @@ export const ru = {
|
|
|
177
186
|
'contract/stream-error': 'поток операции {op} завершился ошибкой сервера ({code})',
|
|
178
187
|
'contract/heartbeat-missed': 'поток операции {op} молчал {ms} мс',
|
|
179
188
|
//#endregion
|
|
189
|
+
|
|
190
|
+
//#region calendar language (the date names, relative phrasing and
|
|
191
|
+
// format display names of @jarenjs/locales' date adapter)
|
|
192
|
+
// The month names are the FORMAT (genitive) forms, because the array
|
|
193
|
+
// feeds a date pattern ('d MMMM yyyy' reads '27 июля 2026'), not a
|
|
194
|
+
// standalone label. Both 'назад' and 'через' take the accusative, so
|
|
195
|
+
// one set of counted forms serves past and future alike.
|
|
196
|
+
...dateNameEntries({
|
|
197
|
+
months: [
|
|
198
|
+
'января', 'февраля', 'марта', 'апреля', 'мая', 'июня',
|
|
199
|
+
'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря',
|
|
200
|
+
],
|
|
201
|
+
monthsShort: [
|
|
202
|
+
'янв.', 'февр.', 'мар.', 'апр.', 'мая', 'июн.',
|
|
203
|
+
'июл.', 'авг.', 'сент.', 'окт.', 'нояб.', 'дек.',
|
|
204
|
+
],
|
|
205
|
+
weekdays: [
|
|
206
|
+
'воскресенье', 'понедельник', 'вторник', 'среда',
|
|
207
|
+
'четверг', 'пятница', 'суббота',
|
|
208
|
+
],
|
|
209
|
+
weekdaysShort: [
|
|
210
|
+
'вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб',
|
|
211
|
+
],
|
|
212
|
+
meridiem: ['AM', 'PM'],
|
|
213
|
+
}),
|
|
214
|
+
'date/relative/second/past': (p) => `${num(p.value)} ${caseForms(p.value, { one: 'секунду', few: 'секунды', other: 'секунд' })} назад`,
|
|
215
|
+
'date/relative/second/future': (p) => `через ${num(p.value)} ${caseForms(p.value, { one: 'секунду', few: 'секунды', other: 'секунд' })}`,
|
|
216
|
+
'date/relative/minute/past': (p) => `${num(p.value)} ${caseForms(p.value, { one: 'минуту', few: 'минуты', other: 'минут' })} назад`,
|
|
217
|
+
'date/relative/minute/future': (p) => `через ${num(p.value)} ${caseForms(p.value, { one: 'минуту', few: 'минуты', other: 'минут' })}`,
|
|
218
|
+
'date/relative/hour/past': (p) => `${num(p.value)} ${caseForms(p.value, { one: 'час', few: 'часа', other: 'часов' })} назад`,
|
|
219
|
+
'date/relative/hour/future': (p) => `через ${num(p.value)} ${caseForms(p.value, { one: 'час', few: 'часа', other: 'часов' })}`,
|
|
220
|
+
'date/relative/day/past': (p) => `${num(p.value)} ${caseForms(p.value, { one: 'день', few: 'дня', other: 'дней' })} назад`,
|
|
221
|
+
'date/relative/day/future': (p) => `через ${num(p.value)} ${caseForms(p.value, { one: 'день', few: 'дня', other: 'дней' })}`,
|
|
222
|
+
'date/relative/week/past': (p) => `${num(p.value)} ${caseForms(p.value, { one: 'неделю', few: 'недели', other: 'недель' })} назад`,
|
|
223
|
+
'date/relative/week/future': (p) => `через ${num(p.value)} ${caseForms(p.value, { one: 'неделю', few: 'недели', other: 'недель' })}`,
|
|
224
|
+
'date/relative/month/past': (p) => `${num(p.value)} ${caseForms(p.value, { one: 'месяц', few: 'месяца', other: 'месяцев' })} назад`,
|
|
225
|
+
'date/relative/month/future': (p) => `через ${num(p.value)} ${caseForms(p.value, { one: 'месяц', few: 'месяца', other: 'месяцев' })}`,
|
|
226
|
+
'date/relative/year/past': (p) => `${num(p.value)} ${caseForms(p.value, { one: 'год', few: 'года', other: 'лет' })} назад`,
|
|
227
|
+
'date/relative/year/future': (p) => `через ${num(p.value)} ${caseForms(p.value, { one: 'год', few: 'года', other: 'лет' })}`,
|
|
228
|
+
'date/relative/now': 'сейчас',
|
|
229
|
+
'date/relative/yesterday': 'вчера',
|
|
230
|
+
'date/relative/today': 'сегодня',
|
|
231
|
+
'date/relative/tomorrow': 'завтра',
|
|
232
|
+
'format/name/date': 'дата',
|
|
233
|
+
'format/name/time': 'время',
|
|
234
|
+
'format/name/date-time': 'дата и время',
|
|
235
|
+
'format/name/iso-date': 'дата ISO',
|
|
236
|
+
'format/name/iso-time': 'время ISO',
|
|
237
|
+
'format/name/iso-date-time': 'дата и время ISO',
|
|
238
|
+
//#endregion
|
|
180
239
|
};
|
package/src/tr.js
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
formatMessageValue,
|
|
26
26
|
makeNumberRenderer,
|
|
27
27
|
makeTypeNamer,
|
|
28
|
+
dateNameEntries,
|
|
28
29
|
} from './helpers.js';
|
|
29
30
|
|
|
30
31
|
//#region Intl singletons
|
|
@@ -164,4 +165,52 @@ export const tr = {
|
|
|
164
165
|
'contract/stream-error': '{op} işleminin akışı bir sunucu hatasıyla sona erdi ({code})',
|
|
165
166
|
'contract/heartbeat-missed': '{op} işleminin akışı {ms} ms boyunca sessiz kaldı',
|
|
166
167
|
//#endregion
|
|
168
|
+
|
|
169
|
+
//#region calendar language (the date names, relative phrasing and
|
|
170
|
+
// format display names of @jarenjs/locales' date adapter)
|
|
171
|
+
// Turkish nouns stay singular after a numeral, and 'once'/'sonra'
|
|
172
|
+
// follow the noun, so no suffix ever attaches to interpolated text.
|
|
173
|
+
...dateNameEntries({
|
|
174
|
+
months: [
|
|
175
|
+
'Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran',
|
|
176
|
+
'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık',
|
|
177
|
+
],
|
|
178
|
+
monthsShort: [
|
|
179
|
+
'Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz',
|
|
180
|
+
'Tem', 'Ağu', 'Eyl', 'Eki', 'Kas', 'Ara',
|
|
181
|
+
],
|
|
182
|
+
weekdays: [
|
|
183
|
+
'Pazar', 'Pazartesi', 'Salı', 'Çarşamba',
|
|
184
|
+
'Perşembe', 'Cuma', 'Cumartesi',
|
|
185
|
+
],
|
|
186
|
+
weekdaysShort: [
|
|
187
|
+
'Paz', 'Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cmt',
|
|
188
|
+
],
|
|
189
|
+
meridiem: ['ÖÖ', 'ÖS'],
|
|
190
|
+
}),
|
|
191
|
+
'date/relative/second/past': (p) => `${num(p.value)} saniye önce`,
|
|
192
|
+
'date/relative/second/future': (p) => `${num(p.value)} saniye sonra`,
|
|
193
|
+
'date/relative/minute/past': (p) => `${num(p.value)} dakika önce`,
|
|
194
|
+
'date/relative/minute/future': (p) => `${num(p.value)} dakika sonra`,
|
|
195
|
+
'date/relative/hour/past': (p) => `${num(p.value)} saat önce`,
|
|
196
|
+
'date/relative/hour/future': (p) => `${num(p.value)} saat sonra`,
|
|
197
|
+
'date/relative/day/past': (p) => `${num(p.value)} gün önce`,
|
|
198
|
+
'date/relative/day/future': (p) => `${num(p.value)} gün sonra`,
|
|
199
|
+
'date/relative/week/past': (p) => `${num(p.value)} hafta önce`,
|
|
200
|
+
'date/relative/week/future': (p) => `${num(p.value)} hafta sonra`,
|
|
201
|
+
'date/relative/month/past': (p) => `${num(p.value)} ay önce`,
|
|
202
|
+
'date/relative/month/future': (p) => `${num(p.value)} ay sonra`,
|
|
203
|
+
'date/relative/year/past': (p) => `${num(p.value)} yıl önce`,
|
|
204
|
+
'date/relative/year/future': (p) => `${num(p.value)} yıl sonra`,
|
|
205
|
+
'date/relative/now': 'şimdi',
|
|
206
|
+
'date/relative/yesterday': 'dün',
|
|
207
|
+
'date/relative/today': 'bugün',
|
|
208
|
+
'date/relative/tomorrow': 'yarın',
|
|
209
|
+
'format/name/date': 'tarih',
|
|
210
|
+
'format/name/time': 'saat',
|
|
211
|
+
'format/name/date-time': 'tarih ve saat',
|
|
212
|
+
'format/name/iso-date': 'ISO tarih',
|
|
213
|
+
'format/name/iso-time': 'ISO saat',
|
|
214
|
+
'format/name/iso-date-time': 'ISO tarih ve saat',
|
|
215
|
+
//#endregion
|
|
167
216
|
};
|
package/src/zh-tw.js
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
formatMessageValue,
|
|
27
27
|
makeNumberRenderer,
|
|
28
28
|
makeTypeNamer,
|
|
29
|
+
dateNameEntries,
|
|
29
30
|
} from './helpers.js';
|
|
30
31
|
|
|
31
32
|
//#region Intl singletons
|
|
@@ -165,4 +166,52 @@ export const zhTW = {
|
|
|
165
166
|
'contract/stream-error': '操作 {op} 的串流以伺服器錯誤結束({code})',
|
|
166
167
|
'contract/heartbeat-missed': '操作 {op} 的串流沉默了 {ms} 毫秒',
|
|
167
168
|
//#endregion
|
|
169
|
+
|
|
170
|
+
//#region calendar language (the date names, relative phrasing and
|
|
171
|
+
// format display names of @jarenjs/locales' date adapter)
|
|
172
|
+
// No plural, and the wide and abbreviated month names are the same
|
|
173
|
+
// string - as CLDR has them.
|
|
174
|
+
...dateNameEntries({
|
|
175
|
+
months: [
|
|
176
|
+
'1月', '2月', '3月', '4月', '5月', '6月',
|
|
177
|
+
'7月', '8月', '9月', '10月', '11月', '12月',
|
|
178
|
+
],
|
|
179
|
+
monthsShort: [
|
|
180
|
+
'1月', '2月', '3月', '4月', '5月', '6月',
|
|
181
|
+
'7月', '8月', '9月', '10月', '11月', '12月',
|
|
182
|
+
],
|
|
183
|
+
weekdays: [
|
|
184
|
+
'星期日', '星期一', '星期二', '星期三',
|
|
185
|
+
'星期四', '星期五', '星期六',
|
|
186
|
+
],
|
|
187
|
+
weekdaysShort: [
|
|
188
|
+
'週日', '週一', '週二', '週三', '週四', '週五', '週六',
|
|
189
|
+
],
|
|
190
|
+
meridiem: ['上午', '下午'],
|
|
191
|
+
}),
|
|
192
|
+
'date/relative/second/past': (p) => `${num(p.value)} 秒前`,
|
|
193
|
+
'date/relative/second/future': (p) => `${num(p.value)} 秒後`,
|
|
194
|
+
'date/relative/minute/past': (p) => `${num(p.value)} 分鐘前`,
|
|
195
|
+
'date/relative/minute/future': (p) => `${num(p.value)} 分鐘後`,
|
|
196
|
+
'date/relative/hour/past': (p) => `${num(p.value)} 小時前`,
|
|
197
|
+
'date/relative/hour/future': (p) => `${num(p.value)} 小時後`,
|
|
198
|
+
'date/relative/day/past': (p) => `${num(p.value)} 天前`,
|
|
199
|
+
'date/relative/day/future': (p) => `${num(p.value)} 天後`,
|
|
200
|
+
'date/relative/week/past': (p) => `${num(p.value)} 週前`,
|
|
201
|
+
'date/relative/week/future': (p) => `${num(p.value)} 週後`,
|
|
202
|
+
'date/relative/month/past': (p) => `${num(p.value)} 個月前`,
|
|
203
|
+
'date/relative/month/future': (p) => `${num(p.value)} 個月後`,
|
|
204
|
+
'date/relative/year/past': (p) => `${num(p.value)} 年前`,
|
|
205
|
+
'date/relative/year/future': (p) => `${num(p.value)} 年後`,
|
|
206
|
+
'date/relative/now': '現在',
|
|
207
|
+
'date/relative/yesterday': '昨天',
|
|
208
|
+
'date/relative/today': '今天',
|
|
209
|
+
'date/relative/tomorrow': '明天',
|
|
210
|
+
'format/name/date': '日期',
|
|
211
|
+
'format/name/time': '時間',
|
|
212
|
+
'format/name/date-time': '日期與時間',
|
|
213
|
+
'format/name/iso-date': 'ISO 日期',
|
|
214
|
+
'format/name/iso-time': 'ISO 時間',
|
|
215
|
+
'format/name/iso-date-time': 'ISO 日期與時間',
|
|
216
|
+
//#endregion
|
|
168
217
|
};
|