Skip to content

Lightweight, production-ready CLI for translation data (i18n) management

License

Notifications You must be signed in to change notification settings

maasasia/donggu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

65 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Donggu

๋™๊ตฌ๋Š” ๋‹ค๊ตญ์–ด ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๊ฐ€๋ณ์ง€๋งŒ ๊ฐ•๋ ฅํ•œ 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๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ๊ฐ„ํŽธํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. generated code example

๋‹ค์–‘ํ•œ ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ ๋‚ด๋ณด๋‚ด๊ณ  ๋“ค์–ด์˜ค๊ธฐ

๋™๊ตฌ๋Š” 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์€ ๋ฒˆ์—ญ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋Š” ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

์•„๋ž˜์—์„œ ๋ณด๋‹ค ์ž์„ธํ•œ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์„ธ์š”.

์‚ฌ์šฉ๋ฐฉ๋ฒ•

๋™๊ตฌ์˜ ์ฃผ์š” ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ

๋™๊ตฌ์˜ ํ”„๋กœ์ ํŠธ๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํŒŒ์ผ (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}
]

CLI๋กœ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

์œ„์™€ ๊ฐ™์€ ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ์€ ๋™๊ตฌ๋ฅผ ์ด์šฉํ•ด ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์€ ํด๋”๋กœ ์ด๋™ํ•ด

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|,}

์œ„์™€ ๊ฐ™์ด #{ํ‚ค|์ž๋ฃŒํ˜•|ํฌ๋งท}์˜ ํ˜•ํƒœ๋กœ ํ…œํ”Œ๋ฆฟ์„ ์ •์˜ํ•ด ํฌ๋งท์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ํฌ๋งท์˜ ํ˜•ํƒœ๋Š” ์ž๋ฃŒํ˜•๋งˆ๋‹ค ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

int, float ํฌ๋งท

์ˆซ์ž์˜ ํฌ๋งท์€ 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 ํฌ๋งท

bool ํฌ๋งท์€ ์ฐธ, ๊ฑฐ์ง“์ผ๋•Œ์˜ ๊ฐ’์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ํฌ๋งท์˜ ํ˜•ํƒœ๋Š” (์ฐธ์ผ๋•Œ ๊ฐ’),(๊ฑฐ์ง“์ผ๋•Œ ๊ฐ’)์˜ ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค.

  • ํšŒ์›์˜ ๊ณผ๊ฑฐ ๊ฒฐ์ œ ์ด๋ ฅ: #{HAS_HISTORY|bool|์žˆ์Œ,์—†์Œ}
  • ์ง€๊ธˆ์€ ์„œ๋น„์Šค ์ด์šฉ์ด #{AVAILABLE|bool|๊ฐ€๋Šฅ,๋ถˆ๊ฐ€๋Šฅ}ํ•ฉ๋‹ˆ๋‹ค.

bool ํฌ๋งท์€ ํ…์ŠคํŠธ์˜ ์ผ๋ถ€๋ฅผ ๋™์ ์œผ๋กœ ๋งŒ๋“ค๋•Œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฉฐ, ํ…์ŠคํŠธ ์ „์ฒด์— ๋Œ€ํ•œ ๋ถ„๊ธฐ๋ฅผ ํ•˜๋Š” ๋ฐ ์ด์šฉํ•˜๋Š” ๊ฒƒ์€ ์ข‹์ง€ ๋ชปํ•œ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜ ํ…์ŠคํŠธ๋Š” ํ…์ŠคํŠธ ๋‚ด์šฉ ์ „์ฒด๋ฅผ ํ…œํ”Œ๋ฆฟ์˜ ์ฐธ/๊ฑฐ์ง“์— ์˜์กดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” ๋‘๊ฐœ๋กœ ํ•ญ๋ชฉ์œผ๋กœ ์ชผ๊ฐœ์„œ ๋‚ด์šฉ์„ ๋‹ด๋Š” ๊ฒƒ์ด ํ…์ŠคํŠธ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ๋” ์ข‹๊ณ , ๋ฒˆ์—ญ ์ž‘์—…๋„ ๋ณด๋‹ค ์›ํ• ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

"message_page_title": { "ko": "#{CAN_SEND_MESSAGE|bool|๋ฐœ์†ก ๊ฐ€๋Šฅ,๋ฐœ์†ก ๋ถˆ๊ฐ€}" }

string ํฌ๋งท

string์€ ํฌ๋งท์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

plural ํฌ๋งท

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

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์—์„œ ๋‹ค๊ตญ์–ด ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. 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

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์„ ํ•ฉ์น˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค.

ํ”„๋กœ์ ํŠธ ๋ฐ์ดํ„ฐ (content.json)

{
  "page1": {
    "ko": "1ํŽ˜์ด์ง€",
    "en": "Page 1"
  },
  "hello": {
    "ko": "์•ˆ๋…•",
    "ja": "ใ“ใ‚“ใซใกใฏ"  
  }
}

์™ธ๋ถ€ ๋ฐ์ดํ„ฐ (import.json)

{
  "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๋Š” ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ๋ฎ์–ด์”Œ์›Œ์กŒ์Šต๋‹ˆ๋‹ค.

CLI

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.

License

MIT

About

Lightweight, production-ready CLI for translation data (i18n) management

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages