C# Winform Localization 질문

μ΄λ²ˆμ— Winform으둜 ν•œκ΅­μ–΄,μ˜μ–΄λ₯Ό μ‚¬μš©ν•˜λŠ” ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
νΌμ—μ„œ 기본적으둜 μ§€μ›ν•˜λŠ” Localizable = true둜 μ‚¬μš©ν•˜μ—¬ 각 νΌλ§ˆλ‹€ resxνŒŒμΌμ„ μ–Έμ–΄ λ³„λ‘œ μƒμ„±ν•˜μ—¬
λ²ˆμ—­ 본을 λ§Œλ“€λ‹€ λ³΄λ‹ˆ 폼이 λ§Žμ•„μ§ˆ 수둝 μž‘μ—…μ΄ νž˜λ“€μ–΄ μ§€λ”λΌκ³ μš”β€¦
그리고 폼 λ””μžμΈμ„ μˆ˜μ •ν•  λ•Œλ§ˆλ‹€ λ‹€λ₯Έ μ–Έμ–΄μ˜ resxνŒŒμΌμ€ μˆ˜μ •μ΄ λ˜μ§€ μ•Šμ•„ 일일이 λ³΅μ‚¬ν•˜μ—¬ μƒˆλ‘œ λΆ™μ—¬ λ„£λŠ” μ‹μœΌλ‘œ μž‘μ—…ν•˜μ˜€μŠ΅λ‹ˆλ‹€β€¦

이후 ν”„λ‘œμ νŠΈμ—μ„œ μ§€μ—­ν™”λ₯Ό μ§„ν–‰ν•  λ•ŒλŠ” μ „μ—­μ˜ λ¦¬μ†ŒμŠ€ 파일둜 κ΄€λ¦¬ν•˜μ—¬μ•Ό ν•  λ“―ν•œλ°β€¦
각 μ»¨νŠΈλ‘€μ— 바인딩을 μ–΄μ°Œ ν•΄μ•Ό ν•  μ§€ λͺ¨λ₯΄κ² λ„€μš”… ν•˜λ‚˜ν•˜λ‚˜ λ°”μΈλ”©ν•˜λŠ” μ½”λ“œλ₯Ό 직접 λ„£μ–΄μ•Ό ν•˜λŠ” 수 밖에 μ—†λ‚˜μš”?

λ‹€λ₯Έ 뢄듀은 Winformμ—μ„œ μ§€μ—­ν™”λ₯Ό μ–΄λ–»κ²Œ μ§„ν–‰ν•˜λŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€.

1개의 μ’‹μ•„μš”

μ €λŠ” μœˆνΌμ€ 닀루지 μ•Šμ§€λ§Œ, κ°€λŠ₯ν•œ ν•œ λͺ¨λ“  UI 앱을 ν•œκ΅­μ–΄-μ˜μ–΄λ‘œ λ§Œλ“œλŠ” νŽΈμž…λ‹ˆλ‹€.

이 것이 κ°€λŠ₯ν•œ μ΄μœ λŠ” IStringLocalizer λΌλŠ” λ“ λ“ ν•œ 도ꡬ가 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.
이 μΈν„°νŽ˜μ΄μŠ€μ˜ κ΅¬ν˜„ κ°μ²΄λŠ” μ„œλΉ„μŠ€ μ»¨ν…Œμ΄λ„ˆμ—μ„œ μ œκ³΅ν•˜λŠ” 것이라, μœˆνΌμ—μ„œλŠ” μ‚¬μš©ν•  수 없을 κ²ƒμž…λ‹ˆλ‹€.

윈폼의 지역화와 λ‹€λ₯Έ 도ꡬλ₯Ό μ‚¬μš©ν–ˆμ§€λ§Œ, μ§€μ—­ν™”λ₯Ό ν•˜λ©΄μ„œ λŠλ‚€ 점을 κ³΅μœ ν•΄λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

  1. μžμ› 파일 κ΄€λ¦¬λŠ” μ–΄λ ΅λ‹€.

μ§€μ—­ν™” μžμ›μ„ κ΄€λ¦¬ν•˜λŠ” 것 μžμ²΄κ°€ μ‰¬μš΄ 일은 μ•„λ‹™λ‹ˆλ‹€.
λ·° λ§ˆλ‹€ μ§€μ—­ν™” νŒŒμΌμ„ λ§Œλ“€μ–΄ 보기도 ν•˜κ³ , 전역적인 νŒŒμΌμ„ λ§Œλ“€μ–΄ 보기도 ν•˜κ³ , 도메인 클래슀 λ§ˆλ‹€ μ§€μ—­ν™” νŒŒμΌμ„ λ§Œλ“€κΈ°λ„ ν•΄λ΄€μ§€λ§Œ, 방법 λ³„λ‘œ 큰 μ°¨μ΄λŠ” μ—†μ—ˆμŠ΅λ‹ˆλ‹€.

  1. 짧은 λ¬Έμž₯λ³΄λ‹€λŠ” κΈ΄ λ¬Έμž₯

ν•œκ΅­μ–΄μ™€ λ²ˆμ—­μ–΄ 사이에 λ¬Έμžμ—΄ 길이에 차이가 있기 λ§ˆλ ¨μž…λ‹ˆλ‹€. 근데, 이 차이가 λ””μžμΈ 확정을 μ–΄λ ΅κ²Œ ν•©λ‹ˆλ‹€. κ·Έλž˜μ„œ 가급적 λ¬Έμžμ—΄μ„ 길이λ₯Ό λ§žμΆ”λ„λ‘ λ…Έλ ₯ν–ˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄,

ν•œ: β€œμ‚­μ œλ˜λ©΄ 볡ꡬ할 수 μ—†μŠ΅λ‹ˆλ‹€.”
영: β€œItems will not be recoverable.”

μΆ”κ°€:
μ΄λŸ¬ν•œ 길이 λ§žμΆ€λ„, μ™Έκ΅­μ–΄ ν°νŠΈκ°€ λͺ¨λ…Έ 슀페이슀(λͺ¨λ“  문자의 폭이 κ°™μŒ)일 λ•Œ μ˜λ―Έκ°€ μžˆμ§€, μ•„λ‹ˆλΌλ©΄ λΆ€μ§ˆμ—†μŠ΅λ‹ˆλ‹€.

그런데, 보톡 μœ„μ™€ 같은 짧은 λ¬Έμž₯은 길이λ₯Ό λ§žμΆ”λŠ” 게 νž˜λ“­λ‹ˆλ‹€.
λ§žμΆ˜λ‹€ ν•˜λ”λΌλ„, ν•œκ΅­μ–΄λ“  λ²ˆμ—­μ–΄λ“  ν‘œν˜„μ΄ μ‰½κ²Œ μ–΄μƒ‰ν•΄μ§‘λ‹ˆλ‹€.
λ˜ν•œ, 이 ν—ˆμ ‘ν•œ κ²°κ³Όλ₯Ό μœ„ν•΄, νˆ¬μž…λ˜μ–΄μ•Ό ν•˜λŠ” μ‹œκ°„λ„ 만만치 μ•ŠμŠ΅λ‹ˆλ‹€.

κ·Έλž˜μ„œ, λ©”μ‹œμ§€λŠ” 가급적 κΈ΄ λ¬Έμž₯으둜 μƒμ •ν•˜κ³ , 이λ₯Ό μœ„ν•΄ λ””μžμΈλ„ λ„‰λ„‰νžˆ κ³ λ €ν•˜κ±°λ‚˜, λ””μžμΈκ³Ό λ¬΄κ΄€ν•œ μ‹œμŠ€ν…œ λ©”μ‹œμ§€ λ°•μŠ€λ₯Ό 적극 μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.

  1. μ•„μ΄μ½˜ + 툴팁.

μ½˜νŠΈλ‘€μ— λ¬Έμžμ—΄μ„ μž…νžˆλŠ” 것보닀, μ•„μ΄μ½˜μ„ μ“°λŠ” 것이 λ””μžμΈ 톡일 μΈ‘λ©΄μ—μ„œ μœ λ¦¬ν•©λ‹ˆλ‹€.
μ„€λͺ…이 ν•„μš”ν•œ 경우, μ½˜νŠΈλ‘€μ— νˆ΄νŒμ„ λΆ€μ—¬ν•˜κ³ , 툴팁 λ©”μ‹œμ§€λ₯Ό μ§€μ—­ν™” ν•˜λŠ” 것이죠.
VS 도 λ³΄μ‹œλ©΄, 생각보닀 λ§Žμ€ νˆ΄νŒμ„ μ μš©ν•˜κ³  μžˆμŒμ„ μ•„μ‹€ κ²ƒμž…λ‹ˆλ‹€.
λ¬Έμ œλŠ” μ•„μ΄μ½˜μ€ 개발 업무가 μ•„λ‹ˆλΌ λ””μžμ΄λ„ˆμ˜ μ—…λ¬΄λΌλŠ” 점이죠.
λ””μžμ΄λ„ˆκ°€ μ—†λ‹€λ©΄ μ•„μ΄μ½˜ 동λƒ₯ 많이 λ‹€λ…€μ•Ό ν•©λ‹ˆλ‹€.

  1. 개발 λΉ„μš©

λ³΄μ‹œλ©΄ μ•„μ‹œκ² μ§€λ§Œ, μ§€μ—­ν™”λŠ” 적지 μ•Šμ€ μΆ”κ°€ 업무λ₯Ό μœ λ°œν•©λ‹ˆλ‹€.
제 μƒκ°μ—λŠ” μ§€μ—­ν™”λ₯Ό ν•˜κ² λ‹€κ³  κ²°μ •ν–ˆμœΌλ©΄, λ°˜λ“œμ‹œ μΆ”κ°€ 인λ ₯이 νˆ¬μž…λ˜μ–΄μ•Ό ν•  것 κ°™μŠ΅λ‹ˆλ‹€.
μ–΄μ„€ν”„κ²Œ ν–ˆλ‹€κ°„ λ””μžμΈμ΄ 망가져 μ΄Œν‹°κ°€ λ‚˜κ±°λ‚˜, λ¬Έμžμ—΄ 문제둜 개발 기간이 ꡉμž₯히 κΈΈμ–΄μ§€κ±°λ‚˜, 미완성인 μ±„λ‘œ μΆœμ‹œν•˜κ±°λ‚˜β€¦

μ˜ˆμ‚°μ˜ μΆ”κ°€ νˆ¬μž…μ΄ μ—†μœΌλ©΄, μ§€μ—­ν™”κ°€ λ…μœΌλ‘œ μž‘μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

3개의 μ’‹μ•„μš”

ν˜„μž¬ .net framework 4.8 winforms ν”„λ‘œμ νŠΈμ— μ§€μ—­ν™” μž‘μ—…μ΄ ν•„μš”ν•΄μ„œ μž‘μ—…μ„ μ§„ν–‰ν–ˆμ—ˆλŠ”λ°μš”.

@hyeonjin λ‹˜ 처럼 각 폼 λ³„λ‘œ Localizable 속성을 톡해 μ§€μ—­ν™” μž‘μ—…μ„ μ§„ν–‰ ν–ˆμŠ΅λ‹ˆλ‹€.

winformsμ—μ„œλŠ” μ§€μ—­ν™” μž‘μ—…μ΄ 폼에 μžˆλŠ” Localizable 속성을 톡해 Form.{locale}.resx μƒμ„±ν•˜κ³  Applicationμ—μ„œ CultureInfo둜 λ¦¬μ†ŒμŠ€ μ§€μ—­ν™” νŒŒμΌμ„ λ‘œλ“œν•˜λŠ” μˆ˜λ°–μ— μ—†λŠ” 것 κ°™λ”λΌκ³ μš”. (λ‹€λ₯Έ 방법이 μžˆλŠ”μ§€λŠ” μ°Ύμ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.)

μ €λŠ” μ§€μ—­ν™”λ₯Ό μ§„ν–‰ν•  λ•Œ λ””μžμΈ νƒ€μž„μ—μ„œ κ΄€λ¦¬λ˜λŠ” 것듀은 (Label.Text λ“±) Form.{locale}.resx둜 관리λ₯Ό ν•˜κ³  있고 λŸ°νƒ€μž„μ—μ„œ μ§€μ—­ν™”κ°€ ν•„μš”ν•œ 것듀은(MessageBox λ“±) Resources νŒŒμΌμ„ λ”°λ‘œ λ§Œλ“€μ–΄μ„œ ν…μŠ€νŠΈλ§Œ κ΄€λ¦¬ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. (Resources.{locale}.resx)

λ¦¬μ†ŒμŠ€μ—μ„œ 컨트둀 속성을 applyν•˜λŠ” μˆœμ„œκ°€β€¦ μ œκ°€ λΆ„μ„ν•œ κ²ƒμœΌλ‘œλŠ” Form.{locale}.resx에 ν•΄λ‹Ή 컨트둀의 νƒœκ·Έκ°€ μ—†μœΌλ©΄ Form.resx에 μžˆλŠ” νƒœκ·Έλ‘œ 적용이 λ˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

ν•΄λ‹Ή 컨트둀 parent Form의 Language 속성이 (κΈ°λ³Έκ°’)이 μ•„λ‹Œ 경우 속성을 μˆ˜μ •ν•˜κΈ°λ§Œν•΄λ„ Form.{locale}.resx에 μˆ˜μ •λœ μ†μ„±μœΌλ‘œ νƒœκ·Έκ°€ μƒκΈ°λ”λΌκ³ μš”.

# Form.resx

<data name="button1.Location" type="System.Drawing.Point, System.Drawing">
     <value>240, 64</value>
  </data>
  <data name="button1.Text" xml:space="preserve">
    <value>ν…ŒμŠ€νŠΈ</value>
  </data>
# Form.ja.resx

# Parent Form Language 속성이 일본어인 경우 button1을 λ””μžμΈ νƒ€μž„μ—μ„œ μœ„μΉ˜ 이동을 ν•œ 경우 μƒκΈ°κ²Œ λ©λ‹ˆλ‹€.
<data name="button1.Location" type="System.Drawing.Point, System.Drawing">
    <value>326, 126</value>
  </data>
  <data name="button1.Text" xml:space="preserve">
    <value>ν…ŒμŠ€λ˜</value>
  </data>

그리고 폼 λ””μžμΈμ„ μˆ˜μ •ν•  λ•Œλ§ˆλ‹€ λ‹€λ₯Έ μ–Έμ–΄μ˜ resxνŒŒμΌμ€ μˆ˜μ •μ΄ λ˜μ§€ μ•Šμ•„ 일일이 λ³΅μ‚¬ν•˜μ—¬ μƒˆλ‘œ λΆ™μ—¬ λ„£λŠ” μ‹μœΌλ‘œ μž‘μ—…ν•˜μ˜€μŠ΅λ‹ˆλ‹€β€¦

ν•œλ²ˆμ΄λΌλ„ μˆ˜μ •λœ 속성이 있기 λ•Œλ¬Έμ— (κΈ°λ³Έκ°’)μ—μ„œ μˆ˜μ •μ„ 진행해도 Form.{locale}.resxκ°€ μ•„λ‹Œ Form.resx νƒœκ·Έ 값이 λ°”κ»΄μ„œ μ„œλ‘œ λ‹€λ₯Έ 속성 값을 κ°–κ²Œ λ©λ‹ˆλ‹€. 저도 컨트둀 μœ„μΉ˜λ₯Ό λ°”κΏ¨λŠ”λ° μ–Έμ–΄ λ³„λ‘œ μ„œλ‘œ λ‹€λ₯Έ μœ„μΉ˜μ— μžˆμ–΄μ„œ λ‹Ήν™©ν–ˆμ—ˆλ„€μš”.

μ§€μ—­ν™”λΌλŠ” μž‘μ—…μ΄β€¦ μ΄λ²ˆμ— winformsμ—μ„œ 처음 κ²½ν—˜ν–ˆλŠ”λ° μž‘μ—…λŸ‰μ΄ 만만치 μ•Šλ”λΌκ³ μš”. μ›Ήμ΄λ‚˜ λ‹€λ₯Έ κ³³μ—μ„œ .jsonμ΄λ‚˜ .yml 파일둜 κ΄€λ¦¬ν•˜λŠ” κ²ƒμ²˜λŸΌ winforms은 .resx둜 관리가 λ˜λŠ” 것 κ°™κ³ , 이 λ…Έκ°€λ‹€μ„±? μž‘μ—…μ€ μ–΄μ©” 수 μ—†λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

그런데 κ°€μž₯ κ°€μž₯ 큰 λ¬Έμ œλŠ” MR μ‹œ μ½”λ“œ λ³‘ν•©μ—μ„œ resxκ°€ 좩돌이 λ‚˜λŠ” 경우인 것 κ°™μŠ΅λ‹ˆλ‹€. resxκ°€ 가끔 νƒœκ·Έμ˜ μœ„μΉ˜κ°€ μ„žμ΄κ²Œ λ˜λ©΄μ„œ μΆ©λŒλ‚˜λŠ” κ²½μš°κ°€ μžˆλŠ”λ°β€¦ μ§€μ˜₯을 λ§›λ΄€μŠ΅λ‹ˆλ‹€. :sob::sob:

1개의 μ’‹μ•„μš”