๋๊ตฌ๋ ๋ค๊ตญ์ด ๋ฐ์ดํฐ ๊ด๋ฆฌ๋ฅผ ์ํ ๊ฐ๋ณ์ง๋ง ๊ฐ๋ ฅํ CLI์ ๋๋ค. ๋ฐ์ดํฐ ๊ด๋ฆฌ๋ถํฐ ๋ฒ์ญ๊ฐ์์ ํ ์คํธ ๋ค์ฌ์ค๊ธฐ/๋ด๋ณด๋ด๊ธฐ, ์์ค์ฝ๋์์ ๊ฐํธํ ์ฐ๋ ๋ฑ ํ๋ก๋์ ํ๊ฒฝ์์ ์๊ตฌํ๋ ๋ชจ๋ ์ํฉ์ ๋์ํ ์ ์์ต๋๋ค.
- ์ฃผ์ ๊ธฐ๋ฅ
- ์์ํ๊ธฐ
- ํ๋ก์ ํธ ๊ตฌ์ฑ
- ํ ํ๋ฆฟ ํฌ๋งทํ
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋ ์์ฑ
- ๋ฐ์ดํฐ ๋ด๋ณด๋ด๊ธฐ์ ๋ค์ด์ค๊ธฐ
- CLI
๋ฌธ์์ด๋ก ํ ํ๋ฆฟ์ ๋ง๋ค์ด ๋์ ์ธ ๊ฐ๋ค์ ๋ค๊ตญ์ด ํ ์คํธ์ ์ฝ๊ฒ ํฉ์น ์ ์์ต๋๋ค. ๊ฐ๋ ฅํ ํ ํ๋ฆฟ ๊ธฐ๋ฅ์ ํตํด ๋ค์ํ ํฌ๋งท์ ์๋์ผ๋ก ์ ์ฉํ ์ ์๊ณ , ๋ฒ์ญ๊ฐ์ ๋์์ด๋์๊ฒ ํ ์คํธ์ ๋งฅ๋ฝ์ ์ค๋ช ํ๊ธฐ ์ฌ์์ง๋๋ค.
ํ ํ๋ฆฟ | ์ถ๋ ฅ ์์ |
---|---|
์ด๋๊ฑฐ๋ฆฌ #{DISTANCE|float|6.3}km |
์ด๋๊ฑฐ๋ฆฌย ย ย 1.75km |
ํฌ์ธํธ #{BALANCE|int|8,}์ |
ํฌ์ธํธย ย 123,456์ |
์ฃผํ ์ด๋ ฅ #{HAS_HISTORY|bool|์์,์์} |
์ฃผํ ์ด๋ ฅ ์์ |
Typescript, Typescript React, Go ํ๋ก์ ํธ์์ ์์ฝ๊ฒ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ๋์ ์ผ๋ก ํ ์คํธ๋ฅผ ๋ถ๋ฌ์ฌ ํ์๊ฐ ์๊ณ , ๋น ๋ฅด๋ฉด์๋ ํ์ ์์ ์ฑ์ด ๋ณด์ฅ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ช ๋ น ํ์ค๋ก ์์ฑํ ์ ์์ต๋๋ค.
{
"user.my_page.coupon_count": {
"ko": "#{NAME}๋์ ์ฟ ํฐ์ #{COUNT|int}๊ฐ ๋ณด์ ์ค์
๋๋ค.",
"en": "Hi #{NAME}, you have #{COUNT|int} coupons."
}
}
์ด๋ ๊ฒ ํ
์คํธ๋ฅผ ์ ์ฅํ๊ณ donggu export typescript my-project
๋ฅผ ์คํํ๋ฉด ์๋์ฒ๋ผ ๊ฐํธํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค.
๋๊ตฌ๋ JSON ํํ๋ก ๋ฒ์ญ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ์ง๋ง, ์ธ์ ๋ ์ง CSV ํน์ HTML(์ค๋น์ค) ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ด๋ณด๋ด๊ณ ๋ค์ฌ์ฌ ์ ์์ต๋๋ค. ๋ฒ์ญ๊ฐ์ ๋์์ด๋์๊ฒ ํ์ํ ํ ์คํธ๋ฅผ ์์ฝ๊ฒ ์ ๋ฌํ ์ ์๊ณ , ์์ ๋ ๋ฐ์ดํฐ๋ ๋ช ๋ น ํ๋ฒ์ผ๋ก ํ๋ก์ ํธ์ ๋ค์ด์ฌ ์ ์์ต๋๋ค.
donggu export csv task.csv // ํ์ฌ ํ๋ก์ ํธ๋ฅผ CSV๋ก ๋ด๋ณด๋ด๊ธฐ
donggu merge csv done.csv // ์์
๋ CSV๋ฅผ ํ์ฌ ํ๋ก์ ํธ์ ํฉ์นจ
์ฌ๊ธฐ์์ ์ด๋ค ๋ฐ์ดํฐ๊ฐ ๋ฐ๋์๋์ง์ diff ๋ถ์๋ ์ฝ๊ฒ ๊ฐ๋ฅํฉ๋๋ค.
Releases ํ์ด์ง์์ ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋ค์ด๋ก๋ ํ๊ฑฐ๋, ์ค์น ์คํฌ๋ฆฝํธ๋ฅผ ์ด์ฉํด ๋ค์ด๋ก๋ ํ ์ ์์ต๋๋ค.
wget -O install.sh https://raw.githubusercontent.com/maasasia/donggu/main/install.sh && chmod +x install.sh && ./install.sh
๋ฐ์ด๋๋ฆฌ๊ฐ ์์นํ ํด๋๋ฅผ PATH
์ ์ถ๊ฐํด์ฃผ์ธ์.
๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ ํด๋๋ก ์ด๋ํด ์๋ก์ด ํ๋ก์ ํธ๋ฅผ ์์ฑํฉ๋๋ค.
mkdir my-project && cd my-project
donggu init
ํ์ํ ์ ๋ณด๋ฅผ ์
๋ ฅํ๊ณ ๋๋ฉด metadata.json
๊ณผ content.json
์ด ์์ฑ๋ฉ๋๋ค.
metadata.json
์ ๋ฉํ๋ฐ์ดํฐ ํ์ผ๋ก, ์ง์ํ ์ธ์ด์ ๋ชฉ๋ก๊ณผ ๋ฒ์ ์ ๋ณด๋ฑ์ ๋ด์ต๋๋ค.
content.json
์ ๋ฒ์ญ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ ํ์ผ์
๋๋ค.
์๋์์ ๋ณด๋ค ์์ธํ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.
๋๊ตฌ์ ์ฃผ์ ๊ธฐ๋ฅ์ ์ค๋ช ํฉ๋๋ค.
- ํ๋ก์ ํธ ๊ตฌ์ฑ
- ํ ํ๋ฆฟ ํฌ๋งทํ
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋ ์์ฑ
- ๋ฐ์ดํฐ ๋ด๋ณด๋ด๊ธฐ์ ๋ค์ด์ค๊ธฐ
- CLI
๋๊ตฌ์ ํ๋ก์ ํธ๋ ๋ฉํ๋ฐ์ดํฐ ํ์ผ (metadata.json
), ๋ฐ์ดํฐ ํ์ผ (content.json
)์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
๋ฐ์ดํฐ ํ์ผ์ ์ฌ๋ฌ๊ฐ์ ํ ์คํธ ํญ๋ชฉ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค. ๊ฐ ํ ์คํธ ํญ๋ชฉ์ ๊ณ ์ ํ ํค์ ์ธ์ด๋ณ๋ก ๋์๋๋ ํ ์คํธ๋ก ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค.
๊ฐ ํค๋ .
์ผ๋ก ๋ถ๋ฆฌ๋ ์ฌ๋ฌ ๊ฐ์ snake_case
ํญ๋ชฉ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค. camelCase
๋ PascalCase
๋ฅผ ์ฌ์ฉํด์๋ ์๋๊ณ , ์์ด ์๋ฌธ์, ์ซ์, _
๋ฅผ ์ ์ธํ๊ณ ๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- (X)
common.appTitle
- (X)
common.1page.title
(์ซ์๋ก ์์ํ๋ฉด ์๋จ) - (O)
common.page_1.title
๊ฐ๋จํ ๋ฐ์ดํฐ ํ์ผ์ ๋ง๋ ๋ค๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
{
"user.my_page.welcome": {
"ko": "์ํ์นด ๊ฐ์
์ ํ์ํฉ๋๋ค!",
"en": "Welcome to Alpaca!",
"context": "์ฒ์ ๊ฐ์
ํ์ ๋๋ง ํ์ถ๋๋ ํ
์คํธ"
},
"user.my_page.coupon_count": {
"ko": "#{NAME}๋์ ์ฟ ํฐ์ #{COUNT|int}๊ฐ ๋ณด์ ์ค์
๋๋ค.",
"en": "Hi #{NAME}, you have #{COUNT|int} coupons."
}
}
์ธ์ด๋ ๋ฉํ๋ฐ์ดํฐ ํ์ผ์ ์ค์ ๋ ๊ฐ๋ค๋ง ์ฌ์ฉํ ์ ์๊ณ , ํ์ ์ธ์ด๋ก ์ง์ ๋ ์ธ์ด๋ค์ ๋ฐ๋์ ํฌํจํด์ผ ํฉ๋๋ค.
user.my_page.welcome
๋ฅผ ๋ณด๋ฉด context
๋ผ๋ ํค๊ฐ ์์ต๋๋ค.
์ด ํค๋ ๋ฒ์ญ ํ
์คํธ๊ฐ ์๋๊ณ ํ
์คํธ ํญ๋ชฉ์ด ์ด๋ค ๋งฅ๋ฝ์์ ๋์ค๋ ํ
์คํธ์ธ์ง ์ค๋ช
ํ๋ ์ฃผ์ ์ญํ ์ ํฉ๋๋ค.
์ฌ๊ธฐ์ ์ด๋ค ํ๋ฉด์์ ์ฌ์ฉ๋๋ ํญ๋ชฉ์ธ์ง, ์ด๋ค ์ํฉ์์๋ง ๋์ค๋ ๊ฐ์ธ์ง ๋ฑ์ ์ค๋ช
ํด์ ๋์์ด๋๋ ๋ฒ์ญ๊ฐ๊ฐ ๋งฅ๋ฝ์ ์๋ชป
์ดํดํ ์ํ์ ์ค์ผ ์ ์์ต๋๋ค. context
๋ ํ์๊ฐ ์๋๋ฉฐ, ์์ฑ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋์ ํฌํจ๋์ง ์์ต๋๋ค.
๋ฉํ๋ฐ์ดํฐ ํ์ผ์ ์๋์ ๊ฐ์ ํ๋๋ก ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค.
supported_languages
: ํ๋ก์ ํธ์์ ์ง์ํ๋ ์ธ์ด๋ฅผ ๋ชจ๋ ์ ๋ ฅํฉ๋๋ค.context
๋ฅผ ์ ์ธํ๊ณ ๋ ์ด๋ค ๊ฐ์ด๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํ์์ ๋ฐ๋ผ ์์ ๋กญ๊ฒ ์ฌ์ฉํ๋ฉด ๋๋, 2๊ธ์์ ISO 639-1 ์ฝ๋๋ฅผ ๊ถ์ฅํฉ๋๋ค.required_languages
: ๋ชจ๋ ํ ์คํธ ํญ๋ชฉ์ด ์ง์ํด์ผ ํ๋ ์ธ์ด๋ค์ ๋๋ค. ์ฌ๊ธฐ์ ์๋ ์ธ์ด๋ค์ ๋ชจ๋supported_languages
์ ํฌํจ๋์ด ์์ด์ผ ํฉ๋๋ค.version
: ํ๋ก์ ํธ์ ๋ฒ์ ์ ๋๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋๋ฅผ ์์ฑํ ๋ ์ด ๊ฐ์ ์ด์ฉํฉ๋๋ค.exporter_options
(์ ํ): ๋ด๋ณด๋ด๊ธฐ ํ์๋ณ๋ก ํ์ํ ์ค์ ์ ๋๋ค. ๋ด๋ณด๋ด๊ธฐ ํ์๋ณ๋ก ํ์ํ ์ค์ ์ ๋ค๋ฅด๋ฉฐ, ์ฝ๋ ์์ฑ๊ณผ ๋ด๋ณด๋ด๊ธฐ์ ๋ค์ฌ์ค๊ธฐ์ ์ ๋ฆฌ๋์ด ์์ต๋๋ค.plurals
(์ ํ): ์ธ์ด๋ณ ๋ณต์ํ์ ์ ์์ ๋๋ค.
{
"exporter_options": {
"typescript": {
"packageName": "@maasasia/translation-alpaca"
}
},
"required_languages": ["ko", "en"],
"supported_languages": ["ko", "en", "ja"],
"version": "0.1.3",
"plurals": {
"ko": [
{"op": "==", "value": 1}
]
}
}
์์ ์์๋ฅผ ์ค๋ช ํ๋ฉด, ์ด ํ๋ก์ ํธ๋
- ํ๊ตญ์ด, ์์ด, ์ผ๋ณธ์ด์ ๋ํ ๋ฒ์ญ์ ๋ด๊ณ ์์ผ๋ฉฐ
- ํ๊ตญ์ด, ์์ด๋ ๋ชจ๋ ํ ์คํธ๊ฐ ๋ฒ์ญ๋์ด ์์ง๋ง ์ผ๋ณธ์ด๋ ์ผ๋ถ๋ง ์ง์ํ๊ณ
- ๋ฒ์ ์ 0.1.3์ ๋๋ค.
- Typescript ํจํค์ง๋ฅผ ๋ง๋ค ๋๋ ํจํค์ง๋ช
์ผ๋ก
@maasasia/translation-alpaca
๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๋ฉํ๋ฐ์ดํฐ ํ์ผ์ plurals
ํ๋์๋ ์ธ์ด๋ณ ๋ณต์ํ์ ์ ์ํ ์ ์์ต๋๋ค. ์ด ์ ์๋ plural
ํ
ํ๋ฆฟ ์๋ฃํ์ ์ฌ์ฉ๋ฉ๋๋ค.
supported_languages
์ ํฌํจ๋ ์ธ์ด์ ๋ํด ๋ณต์ํ์ ์ ์ํ ์ ์์ต๋๋ค. ์ ์๋ ์๋์ ๊ฐ์ด op
, value
๋ก ์ด๋ฃจ์ด์ง object์ ๋ฐฐ์ด๋ก ์ด๋ฃจ์ด์ง๋๋ค.
[
{"op": "==", "value": 1},
{"op": "<=", "value": 2},
]
op
์ ๊ฐ๋ฅํ ๊ฐ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
==
:value
์ ์ผ์น (test == value
)<=
,<
,>
,>=
:value
์ ๋น๊ต (test <= value
, ...)%div
:div
๋ก ๋๋ ๋๋จธ์ง๊ฐvalue
์ ์ผ์น (test%div == value
)/div
:div
๋ก ๋๋ ๋ชซ์ดvalue
์ ์ผ์น (test/div ==
value`)
์ด๋ค ๊ฐ์ ๋ณต์ํ์ ํ๋ณํ ๋๋ ๋ฐฐ์ด์ ์์๋๋ก ๊ฐ์ด ์กฐ๊ฑด์ ๋ง์กฑํ๋์ง ํ์ธํ๊ณ , ์ฒซ๋ฒ์งธ๋ก ๋ง์กฑํ๋ ์กฐ๊ฑด์ ๋ณต์ํ์ผ๋ก ํ๋จํฉ๋๋ค.
์์ ๊ฒฝ์ฐ, ์ด๋ค ์ ์ test
์ ๋ณต์ํ์ ํ๋จํ๋ ๋ก์ง์ ์๋์ ๊ฐ์ ์ฝ๋๋ก ๋ณํ๋๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค.
int findPluralCase(int test) {
if (test == 1) {
return 0;
}
if (test <= 2) {
return 1;
}
return 2;
}
๋ณต์ํ์ ์ง์ ํ์ง ์์ ๊ฒฝ์ฐ์๋ ์๋์ ๊ฐ์ ์ ์๊ฐ ์ฌ์ฉ๋ฉ๋๋ค. (1๊ฐ์ธ ๊ฒฝ์ฐ๋ง ๋จ์๋ก ์ทจ๊ธ)
[
{"op": "==", "value": 1}
]
์์ ๊ฐ์ ํ๋ก์ ํธ ๊ตฌ์ฑ์ ๋๊ตฌ๋ฅผ ์ด์ฉํด ์๋์ผ๋ก ์์ฑํ ์ ์์ต๋๋ค. ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๊ณ ์ถ์ ํด๋๋ก ์ด๋ํด
donggu init
ํ ํ์ํ ํ๋๋ฅผ ์ฑ์์ฃผ์ธ์.
ํ ํ๋ฆฟ์ ์ด์ฉํด ๋์ ์ผ๋ก ๋ฐ๋์ด์ผ ํ๋ ํ ์คํธ๋ฅผ ๋ค๊ตญ์ด ํ ์คํธ์ ์ฝ๊ฒ ํฉ์น ์ ์์ต๋๋ค.
"ticket.issued": {
"ko": "์ ๊ธฐ๊ถ '#{TICKET_NAME}'์ด ๋ฐ๊ธ๋์์ต๋๋ค."
}
์์ ๊ฒฝ์ฐ ticket.issued
ํ
์คํธ๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋ ticketName
์ด๋ผ๋ ๋งค๊ฐ๋ณ์๊ฐ ํ์ํ๊ณ , ๊ฐ๋ฐ์๊ฐ TICKET_NAME
์ ์ง์ ๋ฐ๊ฟ ํ์ ์์ด ํจ์์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฃ์ด์ฃผ๋ฏ์ด ์๋์ผ๋ก ์ฒ๋ฆฌํด ์ค ์ ์์ต๋๋ค.
Donggu.ticket.issued({ ticketName: "30์ผ ํ์น๊ถ" });
// ์ ๊ธฐ๊ถ '30์ผ ํ์น๊ถ'์ด ๋ฐ๊ธ๋์์ต๋๋ค.
#{TICKET_NAME}
์ฒ๋ผ ํ
์คํธ๋ฅผ ํ์ํ ๋ ๊ต์ฒด๋๋ ๋ถ๋ถ์ ํ
ํ๋ฆฟ์ด๋ผ๊ณ ํฉ๋๋ค.
ํ
ํ๋ฆฟ์ #{}
๋ก ๊ฐ์ธ์ง๋ฉฐ, ์์ ์ด๋ค ๊ฐ์ธ์ง๋ฅผ ๋ํ๋ด๋ ํ
ํ๋ฆฟ ํค๊ฐ ์์ด์ผ ํฉ๋๋ค.
ํ
ํ๋ฆฟ ํค๋ ๋๋ฌธ์ SNAKE_CASE
์ ํํ์ด์ด์ผ ํฉ๋๋ค. ๋๋ฌธ์ ์ํ๋ฒณ, ์ซ์, _
๋ง ํ์ฉ๋๋ฉฐ ์ฒซ ๊ธ์๋ ๋๋ฌธ์ ์ํ๋ฒณ์ด์ด์ผ ํฉ๋๋ค. ๊ฐ์ ํ
ํ๋ฆฟ ํค๋ ํ ํ
์คํธ์ ์ฌ๋ฌ๋ฒ ๋ฑ์ฅํด๋ ๋์ง๋ง, ๊ณง ์ค๋ช
ํ ์๋ฃํ์ด ์ถฉ๋ํด์๋ ์๋ฉ๋๋ค.
์๋ฃํ์ ์ง์ ํด ํ ํ๋ฆฟ์ ๋ค์ด๊ฐ ๋ฐ์ดํฐ์ ์ข ๋ฅ๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.
๊ฒฐ์ ์์ก: #{BALANCE|int}
์์ ๊ฐ์ ํ
ํ๋ฆฟ์ ๋ง๋ ๋ค๋ฉด ํค BALANCE
๋ฅผ ๊ฐ์ง๋ ์ ์ํ(int
) ํ
ํ๋ฆฟ์ ์๋ฏธํฉ๋๋ค.
|
์ผ๋ก ๋ถ๋ฆฌํ์ฌ ์๋ฃํ์ ์ง์ ํ๋ฉฐ, ์ง์ ํ์ง ์์ ๊ฒฝ์ฐ string
์ ์๋ฃํ์ ๊ฐ์ต๋๋ค.
์๋์ ๊ฐ์ ์๋ฃํ์ด ์กด์ฌํฉ๋๋ค.
- ๋ฌธ์์ด:
string
- ์ ์:
int
- ์ค์:
float
- ๋ถ์ธ:
bool
- ๋จ, ๋ณต์ ์ ํ:
plural
ํ ํ๋ฆฟ์ ๋ค์ด๊ฐ๋ ๊ฐ์ ํฌ๋งท์ ์ง์ ํ ์ ์์ต๋๋ค. ํฌ๋งท ๋์ด์ฐ๊ธฐ, ์ซ์์ ์ผํ ๋ฑ ์ด๋ป๊ฒ ํ ํ๋ฆฟ์ด ํ์๋์ด์ผ ํ๋์ง๋ฅผ ๋ํ๋ ๋๋ค.
๊ฒฐ์ ์์ก: #{BALANCE|int|,}
์์ ๊ฐ์ด #{ํค|์๋ฃํ|ํฌ๋งท}
์ ํํ๋ก ํ
ํ๋ฆฟ์ ์ ์ํด ํฌ๋งท์ ์ง์ ํฉ๋๋ค. ํฌ๋งท์ ํํ๋ ์๋ฃํ๋ง๋ค ๋ค๋ฆ
๋๋ค.
์ซ์์ ํฌ๋งท์ Go, C ๋ฑ์ ์ธ์ด์์ ์ฌ์ฉํ๋ printf ํฌ๋งท์์ %
, d
๋ฅผ ์ ๊ฑฐํ ๊ฒ๊ณผ ์ ์ฌํ ํํ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
float
๋ ์ถ๋ ฅ ๋๋น์ ์์์ ์๋ฆฌ์๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.
#{VALUE|float} ๊ธฐ๋ณธ ๋๋น, ๊ธฐ๋ณธ ์์์ ์๋ฆฌ์
#{VALUE|float|9} ๋๋น 9, ๊ธฐ๋ณธ ์์์ ์๋ฆฌ์
#{VALUE|float|.2} ๊ธฐ๋ณธ ๋๋น, ์์์ 2์๋ฆฌ
#{VALUE|float|9.2} ๋๋น 9, ์์์ 2์๋ฆฌ
#{VALUE|float|9.} ๋๋น 9, ์์์ 0์๋ฆฌ
int
๋ ์ถ๋ ฅ ๋๋น๋ง ์ง์ ํ ์ ์์ต๋๋ค.
#{VALUE|int} ๊ธฐ๋ณธ ๋๋น
#{VALUE|int|9} ๋๋น 9
int
์ float
๋ชจ๋ ๋๋น์ ์์์ ์๋ฆฌ ์ง์ ์ ์ ์๋์ ๊ฐ์ ํ๋๊ทธ๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค.
0 ๊ณต๋ฐฑ ๋์ 0์ผ๋ก ๋น ๊ณต๊ฐ์ ์ฑ์๋๋ค (ํจ๋ฉ์ผ๋ก ์ฌ์ฉํฉ๋๋ค)
, ์ธ์๋ฆฌ๋ง๋ค ์ผํ๋ฅผ ๋ฃ์ด์ค๋๋ค. float์ผ ๊ฒฝ์ฐ ์ ์ ๋ถ๋ถ์๋ง ์ผํ๋ฅผ ๋ฃ์ต๋๋ค.
+ ์์์ด๋๋ผ๋ ๋ถํธ๋ฅผ ํ์ํฉ๋๋ค. ์ฌ์ฉํ์ง ์์ ๊ฒฝ์ฐ ์์์๋ง ๋ถํธ๋ฅผ ํ์ํฉ๋๋ค.
๋๋น, ์์์ , ํ๋๊ทธ๋ ๋ชจ๋ ์กฐํฉํ ์ ์์ต๋๋ค.
ํ ํ๋ฆฟ | ์ค๋ช | ์์ |
---|---|---|
#{VALUE|int|09} |
๋๋น 9, ๋น ๊ณต๊ฐ์ 0์ผ๋ก ์ฑ์ | VALUE=12345 -> 000012345 |
#{VALUE|float|,7.} |
๋๋น 7, ์๋ฆฌ์ 0, ์ธ์๋ฆฌ๋ง๋ค ์ผํ ์ฌ์ฉ | VALUE=1234.56 -> 1,234 |
#{VALUE|int|,} |
๊ธฐ๋ณธ ๋๋น, ์ธ์๋ฆฌ๋ง๋ค ์ผํ ์ฌ์ฉ | VALUE=12345678 -> 12,345,678 |
bool
ํฌ๋งท์ ์ฐธ, ๊ฑฐ์ง์ผ๋์ ๊ฐ์ ์ง์ ํฉ๋๋ค. ํฌ๋งท์ ํํ๋ (์ฐธ์ผ๋ ๊ฐ),(๊ฑฐ์ง์ผ๋ ๊ฐ)
์ ํํ์
๋๋ค.
ํ์์ ๊ณผ๊ฑฐ ๊ฒฐ์ ์ด๋ ฅ: #{HAS_HISTORY|bool|์์,์์}
์ง๊ธ์ ์๋น์ค ์ด์ฉ์ด #{AVAILABLE|bool|๊ฐ๋ฅ,๋ถ๊ฐ๋ฅ}ํฉ๋๋ค.
bool
ํฌ๋งท์ ํ ์คํธ์ ์ผ๋ถ๋ฅผ ๋์ ์ผ๋ก ๋ง๋ค๋๋ง ์ฌ์ฉํด์ผ ํ๋ฉฐ, ํ ์คํธ ์ ์ฒด์ ๋ํ ๋ถ๊ธฐ๋ฅผ ํ๋ ๋ฐ ์ด์ฉํ๋ ๊ฒ์ ์ข์ง ๋ชปํ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋๋ค.์๋ฅผ ๋ค์ด ์๋ ํ ์คํธ๋ ํ ์คํธ ๋ด์ฉ ์ ์ฒด๋ฅผ ํ ํ๋ฆฟ์ ์ฐธ/๊ฑฐ์ง์ ์์กดํ๊ณ ์์ต๋๋ค. ์ด๋ฐ ๊ฒฝ์ฐ๋ ๋๊ฐ๋ก ํญ๋ชฉ์ผ๋ก ์ชผ๊ฐ์ ๋ด์ฉ์ ๋ด๋ ๊ฒ์ด ํ ์คํธ๋ฅผ ์ฌ์ฌ์ฉํ๊ธฐ ๋ ์ข๊ณ , ๋ฒ์ญ ์์ ๋ ๋ณด๋ค ์ํ ํ๊ฒ ํ ์ ์์ต๋๋ค.
"message_page_title": { "ko": "#{CAN_SEND_MESSAGE|bool|๋ฐ์ก ๊ฐ๋ฅ,๋ฐ์ก ๋ถ๊ฐ}" }
string
์ ํฌ๋งท์ ์ง์ํ์ง ์์ต๋๋ค.
plural
ํฌ๋งท์ ๋จ์, ๋ณต์์ ๋ฐ๋ผ ๋ค๋ฅธ ํ
์คํธ๋ฅผ ํ์ํ ์ ์๋๋ก ํฉ๋๋ค.
์ธ์ด๋ณ ๋ณต์ํ์ ํ๋ก์ ํธ์ ๋ฉํ๋ฐ์ดํฐ ํ์ผ์ ์ ์๋ฉ๋๋ค. ๋ฉํ๋ฐ์ดํฐ์ ๋ณต์ํ์ ์ ์ํ๋ ๋ฐฉ๋ฒ์ ๋ฉํ๋ฐ์ดํฐ ์ฌ์ฉ๋ฒ์ ์ฐธ๊ณ ํ์ธ์.
ํฌ๋งท์๋ ์ธ์ด๋ณ๋ก ์ ์ํ ๋ณต์ํ๋ณ๋ก ํ์ํ ๊ฐ์ ์ผํ๋ก ๋ถ๋ฆฌํด ์์ฑํฉ๋๋ค.
์๋ฅผ ๋ค์ด ar
์ธ์ด์ ๋ณต์ํ ์ ์๊ฐ ์๋์ ๊ฐ์ด ๋์ด์๋ค๋ฉด,
"ar": [
{"op": "==", "value": 0},
{"op": "==", "value": 1},
{"op": "==", "value": 2},
{"op": "<=", "value": 10},
{"op": "<", "value": 100}
]
ํ
ํ๋ฆฟ์ ์ฌ์ฉํ ๋์๋ #{VALUE|plural|zero,one,two,few,many,other}
ํํ๋ก ์ ์ด์ฃผ์ด์ผ ํฉ๋๋ค.
ํฌ๋งท์ ์ ์ด์ค ๊ฐ์ ๊ฐ๊ฐ 0
, 1
, 2
, 3~10
, 11~99
, 100 ์ด์(๋๋จธ์ง ๊ฒฝ์ฐ)
์ผ๋ ์ฌ์ฉ๋ฉ๋๋ค.
๊ฐ์ ํค์ ๋ํด plural
์ int
์ ๋์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. plural
๋ง ์ฌ์ฉํ ๊ฒฝ์ฐ์๋ ํ
ํ๋ฆฟ์ ๊ฐ์ผ๋ก ์ ์ํ ๊ฐ์ด ํ์ํฉ๋๋ค.
Choose #{CHOICES|plural|an item,items}.
You have #{COUNT|int} #{COUNT|plural|message,messages}.
๋๊ตฌ์ export
๋ช
๋ น์ผ๋ก ํ๋ก์ ํธ์ ๋ค๊ตญ์ด ๋ฐ์ดํฐ๋ฅผ ์์ค์ฝ๋์์ ์ฌ์ฉํ๊ธฐ ์ํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
donggu export typescript my-project
i18next์ด๋ i18n-node ๋ฑ JSON์ ๋์ ์ผ๋ก ๋ถ๋ฌ์ค๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค๊ณผ ๋ฌ๋ฆฌ, ๋๊ตฌ๋ ํ๋ก์ ํธ์ ๋ฐ์ดํฐ์ ๋ง์ถฐ์ง ์ฝ๋๋ฅผ ๋ฏธ๋ฆฌ ์์ฑํฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ํค๊ฐ ๋๋ฝ๋๊ฑฐ๋ ํ ํ๋ฆฟ์ ํํ๊ฐ ์๋ชป๋๋ ์ค๋ฅ๋ฅผ ํ์ ๊ฒ์ฌ๋ก ์ฌ์ ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค. ๋ ๋ฐํ์์ JSON์ ๋ถ์ํ์ง ์๊ณ ๋ฏธ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๋ฏ๋ก ๋ณด๋ค ๋ฐ์ด๋ ์ฑ๋ฅ์ ๊ธฐ๋ํ ์ ์์ต๋๋ค.
Typescript์์ ๋ค๊ตญ์ด ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ฑํฉ๋๋ค.
donggu export typescript my-project
์์ธํ ์ฌ์ฉ ๋ฐฉ๋ฒ์ Typescript Exporter๋ฅผ ์ฝ์ด์ฃผ์ธ์.
import { Donggu } from "@my-org/translations"; // ๋๊ตฌ๊ฐ ์์ฑํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
// ํ์ฌ ์ฌ์ฉ์์ ์ธ์ด๋ฅผ ํ๋จํ๋ ํจ์. HTTP ์์ฒญ์ Accept-Language ํ์ฑ ๋ฑ์ ์ฌ๊ธฐ์ ์ํํ๋ฉด ๋ฉ๋๋ค.
// ๋ฐฐ์ด์ ์์๋๋ก ์ฐ์ ์์๋ฅผ ๊ฐ์ง๋๋ค.
const languageResolver = () => {
return [getUserLanguage(), 'ko'];
};
const donggu = new Donggu(languageResolver);
console.log(donggu.example.hello({name: "๋๊ตฌ"})); // ๋๊ตฌ๋ ์๋
ํ์ธ์!
Typescript React์์ ๋ค๊ตญ์ด ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ฑํฉ๋๋ค. Typescript ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์ฌํ์ง๋ง, ์ค๋ฐ๊ฟ ์ค์ ๋ฑ React์์ ์ฐ๋์ ๋๋ ๊ธฐ๋ฅ์ด ํฌํจ๋์ด ์์ต๋๋ค.
donggu export ts-react my-project
์์ธํ ์ฌ์ฉ ๋ฐฉ๋ฒ์ Typescript React Exporter๋ฅผ ์ฝ์ด์ฃผ์ธ์.
import { Donggu } from "@my-org/translations"; // ๋๊ตฌ๊ฐ ์์ฑํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
// ํ์ฌ ์ฌ์ฉ์์ ์ธ์ด๋ฅผ ํ๋จํ๋ ํจ์. HTTP ์์ฒญ์ Accept-Language ํ์ฑ ๋ฑ์ ์ฌ๊ธฐ์ ์ํํ๋ฉด ๋ฉ๋๋ค.
// ๋ฐฐ์ด์ ์์๋๋ก ์ฐ์ ์์๋ฅผ ๊ฐ์ง๋๋ค.
const languageResolver = () => {
return [getUserLanguage(), 'ko'];
};
const donggu = new Donggu(languageResolver);
const MyElement = (name: string) => {
return (
<>
{donggu.example.hello({name})}
</>
);
};
// ๋๊ตฌ๋ ์๋
ํ์ธ์!
ReactDOM.render(<MyElement name="๋๊ตฌ">, document.getElementById("root"))
Go์์ ๋ค๊ตญ์ด ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ฑํฉ๋๋ค.
donggu export go my-project
์์ธํ ์ฌ์ฉ ๋ฐฉ๋ฒ์ Go Exporter๋ฅผ ์ฝ์ด์ฃผ์ธ์.
package main
import (
"fmt"
"github.com/my-org/translations"
)
// langResolver๋ ํ์ฌ ์ฌ์ฉ์์ ์ธ์ด๋ฅผ ํ๋จํ๋ ํจ์์
๋๋ค.
// query ํจ์๋ ํ์ฌ ํ์ํ๊ณ ์ ํ๋ ํ
์คํธ ํญ๋ชฉ์ ์ํ๋ ์ธ์ด๊ฐ ์๋์ง ๋ฐํํ๋ ํจ์์
๋๋ค.
// ์ด ํจ์๋ ํญ์ query ๊ฒฐ๊ณผ๊ฐ true์ด๊ฑฐ๋ requiredLang์ ํฌํจ๋์ด ์๋ ๊ฐ์ ๋ฐํํด์ผ ํฉ๋๋ค.
func langResolver(query func(lang string) bool) string {
if query("en") {
return "en"
}
return "ko"
}
func main() {
donggu := translations.NewDonggu(langResolver)
// ๋๊ตฌ๋ ์๋
ํ์ธ์!
fmt.Println(donggu.Example().Hello("๋๊ตฌ"))
}
์์ฑ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ๋ก์ ํธ์ ์ง์ ์ถ๊ฐํ๊ฑฐ๋, ์ธ์ด๋ณ๋ก ์ง์ํ๋ ํจํค์ง ์์คํ ์ ํตํด ์ด์ฉํ ์ ์์ต๋๋ค. ๋ชจ๋ ธ๋ ํฌ๋ฅผ ๊ตฌ์ฑํ๊ฑฐ๋ private package registry๋ฅผ ์ฌ์ฉํ๋ ๋ฑ ๋ค์ํ ์๋๋ฆฌ์ค์ ๋ํ ์ค๋ช ์ ๊ธฐ์กด ํ๋ก์ ํธ์์ ์ฐ๋๋ฅผ ์ฐธ๊ณ ํ์ธ์.
์์ ์ค๋ช ํ ๊ฒ๊ณผ ๊ฐ์ด ๋ค๊ตญ์ด ๋ฐ์ดํฐ์ ์๋ณธ์ ํ๋ก์ ํธ ๋จ์๋ก ๊ด๋ฆฌ๋์ง๋ง, ์ธ๋ถ์ ๊ณต์ ํ๊ธฐ ์ํด ํ๋ก์ ํธ ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฌ ํ์ผ ํํ๋ก ๋ด๋ณด๋ผ ์ ์์ต๋๋ค.
donggu export [๋ด๋ณด๋ผ ํ์ผ ํํ] [๋ด๋ณด๋ผ ํ์ผ๋ช
]
donggu merge
๋ช
๋ น์ผ๋ก ์ฌ๋ฌ ๋ฐ์ดํฐ ํ์ผ์ ํ๋๋ก ํฉ์น ์ ์์ต๋๋ค.
donggu merge [์ธ๋ถ ๋ฐ์ดํฐ ํํ] [์ธ๋ถ ๋ฐ์ดํฐ ํ์ผ๋ช
]
์ธ๋ถ ๋ฐ์ดํฐ ํํ๋ json
, csv
๋ฅผ ์ง์ํฉ๋๋ค.
์๋์ ๊ฐ์ด ํ๋ก์ ํธ๊ฐ ์์นํ ํด๋์์ donggu merge
๋ฅผ ์คํํ๋ฉด ์ธ๋ถ ๋ฐ์ดํฐ(exported.csv
)์ ๋ด์ฉ๋ฌผ์ ํ๋ก์ ํธ ๋ฐ์ดํฐ(content.json
)๊ณผ
ํฉ์น ํ, ๊ฒฐ๊ณผ๋ฌผ์ content.json
์ ์ ์ฅํฉ๋๋ค.
$ ls
content.json metadata.json exported.csv
$ donggu merge csv exported.csv
โ
Done in 0.015s
์ธ๋ถ ๋ฐ์ดํฐ๋ ํ๋ก์ ํธ ๋ฐ์ดํฐ๋ฅผ ํญ์ ๋ฎ์ด์์ฐ์ง๋ง, ๋ ๋ฐ์ดํฐ๊ฐ ์ผ๋ถ๋ง ๊ฒน์น ๊ฒฝ์ฐ์๋ ์ต๋ํ ์๋ณธ ๋ฐ์ดํฐ๋ฅผ ์ ์งํ๊ธฐ ์ํด ๋ ธ๋ ฅํฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ content.json
์ ๊ฐ์ง๋ ํ๋ก์ ํธ๊ฐ ์๊ณ , ์ฌ๊ธฐ์ import.json
์ ํฉ์น๋ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด๋ด
์๋ค.
{
"page1": {
"ko": "1ํ์ด์ง",
"en": "Page 1"
},
"hello": {
"ko": "์๋
",
"ja": "ใใใซใกใฏ"
}
}
{
"hello": {
"ko": "์๋
ํ์ธ์",
"en": "Hello"
},
"page2": {
"ko": "2ํ์ด์ง",
"en": "Page 2"
}
}
๋ ํ์ผ์ ํฉ์น ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
{
"page1": {
"ko": "1ํ์ด์ง",
"en": "Page 1"
},
"page2": {
"ko": "2ํ์ด์ง",
"en": "Page 2"
},
"hello": {
"ko": "์๋
ํ์ธ์",
"en": "Hello",
"ja": "ใใใซใกใฏ"
},
}
page1
์ ํ๋ก์ ํธ ๋ฐ์ดํฐ์๋ ์์ง๋ง ์ธ๋ถ ๋ฐ์ดํฐ์๋ ์์ด ๊ทธ๋๋ก ์ ์ง๋ฉ๋๋ค.page2
๋ ์ธ๋ถ ๋ฐ์ดํฐ์๋ง ์์ด ์๋ก ์ถ๊ฐ๋์์ต๋๋ค.hello
๋ ๋ ๋ฐ์ดํฐ์ ๋ชจ๋ ์๋๋ฐ, ํ๋ก์ ํธ ๋ฐ์ดํฐ์๋ง ์๋ja
ํ ์คํธ๋ ๊ทธ๋๋ก ์ ์ง๋์์ง๋ง ์ธ๋ถ ๋ฐ์ดํฐ์๋ ์๋en
,ko
๋ ์ถ๊ฐ๋๊ฑฐ๋ ๋ฎ์ด์์์ก์ต๋๋ค.
Donggu is a simple cli for managing i18n text data
Usage:
donggu [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
diff Show differences of a content file against the current project
export Export something
fmt Format content and metadata file
help Help about any command
init Initialize new project
merge Merge a content file to the current project
Flags:
-h, --help help for donggu
-P, --project string Project folder (default: current directory)
Use "donggu [command] --help" for more information about a command.
MIT