# თავი 9: ინტერნაციონალიზაცია და ლოკალიზაცია --- ## 9.1 თქვენი აპლიკაციის მულტილინგვურად (მრავალენოვნად) ქცევა აქამდე განხილულ ყველა თავში ვვარაუდობდით, რომ აპლიკაცია ერთენოვანია. ჩვენი თარგები (templates) აჩვენებს ინგლისურ ტექსტს, ვალიდაციის შეტყობინებები ინგლისურადაა და შეცდომის გვერდებიც ინგლისურად "საუბრობენ". ეს მისაღებია, როცა თქვენი აუდიტორია ერთ ენას იზიარებს, თუმცა ბევრ აპლიკაციას სჭირდება სხვადასხვა რეგიონის მომხმარებლების მომსახურება — ეს მომხმარებლები კი მოელიან, რომ ინტერფეისი მათ მშობლიურ ენაზე იქნება. ეს თავი გაგაცნობთ **ინტერნაციონალიზაციას (i18n)** და **ლოკალიზაციას (l10n)** Spring Boot-ში. ჩვენ ვისწავლით, როგორ გადავიტანოთ მომხმარებლისთვის განკუთვნილი ყველა ტექსტი გარე **message bundles**-ში, როგორ განვსაზღვროთ მომხმარებლის ლოკალი (locale), როგორ მივცეთ მათ ენის შეცვლის საშუალება და როგორ გამოვაჩინოთ ლოკალიზებული შეტყობინებები FreeMarker-ის თარგებში. ასევე განვიხილავთ ლოკალიზაციას REST API-ებში, ვალიდაციის შეტყობინებებში, Spring Security-ის გვერდებზე და თარიღებისა და რიცხვების ფორმატირებაში. ბოლოს, ვნახავთ თარგმანების მონაცემთა ბაზაში შენახვის გზას იმ აპლიკაციებისთვის, რომლებსაც დინამიური მართვა სჭირდებათ. --- ## 9.2 ინტერნაციონალიზაცია vs. ლოკალიზაცია ეს ორი ტერმინი დაკავშირებულია, მაგრამ განსხვავებული: **ინტერნაციონალიზაცია (i18n)** არის აპლიკაციის დაპროექტების პროცესი ისე, რომ მას *შეეძლოს* მრავალი ენისა და რეგიონის მხარდაჭერა კოდის ცვლილების გარეშე. ეს გულისხმობს ტექსტების ექსტრაქციას (ამოღებას) თარგებიდან და Java კოდიდან გარე ფაილებში, ასევე თარიღების, რიცხვებისა და ვალუტის ფორმატირებას ლოკალის გათვალისწინებით. i18n არის არქიტექტურული სამუშაო — მას აკეთებთ ერთხელ, რაც შესაძლებელს ხდის ლოკალიზაციას. **ლოკალიზაცია (l10n)** არის აპლიკაციის ადაპტაციის პროცესი კონკრეტული ლოკალისთვის — ტექსტის თარგმნა, თარიღის ფორმატების მორგება და რეგიონული კონვენციების დამუშავება. l10n არის კონტენტის სამუშაო — მას აკეთებთ თითოეული ენისთვის, რომლის მხარდაჭერაც გსურთ. ლოკალიზებული აპლიკაციისთვის ორი რამ არის აუცილებელი: თარგმნილი ტექსტური ფაილები (თითო ენაზე) და მექანიზმი იმის დასადგენად, თუ რომელი ენა სურს მიმდინარე მომხმარებელს. --- ## 9.3 Message Bundles Spring Boot იყენებს **message bundles**-ს — `.properties` ფაილების ნაკრებს, რომლებიც შეიცავენ თარგმნილ ტექსტებს საერთო იდენტიფიკატორით (key). ნაგულისხმევად, Spring Boot ეძებს ფაილებს სახელად `messages.properties` classpath-ზე (`src/main/resources/` დირექტორიაში). სამი ენის მხარდასაჭერად, ქმნით სამ ფაილს: ``` src/main/resources/ ├── messages.properties ← ნაგულისხმევი ენა (fallback) ├── messages_en.properties ← ინგლისური ├── messages_ka.properties ← ქართული └── messages_ru.properties ← რუსული ``` თითოეული ფაილი შეიცავს ერთსა და იმავე გასაღებებს (keys) სხვადასხვა თარგმნილი მნიშვნელობებით. **messages.properties** (ნაგულისხმევი — გამოიყენება მაშინ, როცა კონკრეტული ლოკალის ფაილი არ მოიძებნება): ```properties nav.home=Home nav.about=About Us nav.contact=Contact Us greeting=Welcome to our website! ``` **messages_ka.properties** (ქართული): ```properties nav.home=მთავარი nav.about=ჩვენ შესახებ nav.contact=კონტაქტი greeting=კეთილი იყოს თქვენი მობრძანება! ``` ლოკალის სუფიქსი მიჰყვება ISO 639-1 სტანდარტს — `en` ინგლისურისთვის, `ka` ქართულისთვის და ა.შ. Spring Boot ავტომატურად უსაბამებს მომხმარებლის ლოკალს შესაბამის ფაილს. ### Encoding (კოდირება) `.properties` ფაილების ნაგულისხმევი კოდირებაა ISO-8859-1, რომელიც არ უჭერს მხარს სიმბოლოებს ლათინური ანბანის გარეთ. ქართული ან რუსული ენებისთვის გაქვთ ორი გზა: გამოიყენოთ Unicode escape მიმდევრობები (მაგ: `\u10DB`), ან დააკონფიგურიროთ თქვენი IDE, რომ შეინახოს ფაილები **UTF-8** ფორმატში და `application.properties`-ში დაამატოთ: ```properties spring.messages.encoding=UTF-8 ``` --- ## 9.4 ლოკალიზებული შეტყობინებების ჩვენება FreeMarker-ში FreeMarker წვდება Spring-ის message bundles-ს `spring.ftl` მაკროსების საშუალებით. დააიმპორტეთ ბიბლიოთეკა თარგის თავში და გამოიყენეთ `<@spring.message>` ტექსტის ამოსაღებად: ```html <#import "/spring.ftl" as spring>

<@spring.message "greeting"/>

``` --- ## 9.5 Locale Resolution (ლოკალის განსაზღვრა) Spring Boot-მა უნდა დაადგინოს, რომელი ენა გამოიყენოს თითოეული მოთხოვნისთვის (request). ამას აკეთებს **`LocaleResolver`** — კომპონენტი, რომელიც კითხულობს ლოკალს სხვადასხვა ადგილიდან. | Resolver | შენახვის ადგილი | პერსისტენტულობა | | --- | --- | --- | | `AcceptHeaderLocaleResolver` | HTTP header | მომხმარებელი ვერ ცვლის ხელით. | | `SessionLocaleResolver` | Server-side session | იკარგება სესიის დასრულებისას. | | `CookieLocaleResolver` | Browser cookie | ინახება ბრაუზერის დახურვის შემდეგაც. | ### CookieLocaleResolver-ის კონფიგურაცია ```java @Configuration public class LocaleConfig { @Bean public LocaleResolver localeResolver() { CookieLocaleResolver resolver = new CookieLocaleResolver(); resolver.setDefaultLocale(Locale.ENGLISH); resolver.setCookieMaxAge(Duration.ofDays(30)); resolver.setCookiePath("/"); return resolver; } } ``` --- ## 9.6 ენების გადართვა LocaleChangeInterceptor-ით `LocaleResolver` ინახავს ლოკალს, მაგრამ მის შესაცვლელად საჭიროა ტრიგერი. `LocaleChangeInterceptor` აკვირდება request parameter-ს (ჩვეულებრივ `lang`) და აახლებს ლოკალს მისი არსებობის შემთხვევაში. ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Bean public LocaleChangeInterceptor localeChangeInterceptor() { LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor(); interceptor.setParamName("lang"); return interceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); } } ``` ახლა, URL-ის ბოლოს `?lang=ka` დამატება შეცვლის ენას ქართულზე. --- ## 9.7 ენის გადამრთველის (Language Switcher) აგება მომხმარებელს სჭირდება ვიზუალური გზა ენის შესაცვლელად. უმარტივესი გზაა `select` მენიუ, რომელიც გადამისამართდება მიმდინარე გვერდზე `?lang=` პარამეტრით: ```html ``` --- ## 9.8 ვალიდაციის შეტყობინებების ლოკალიზაცია Bean Validation ანოტაციების შეტყობინებები შეიძლება ლოკალიზდეს ფიგურული ფრჩხილების `{...}` გამოყენებით: ```java @NotBlank(message = "{user.name.notblank}") private String name; ``` შემდეგ შესაბამისი გასაღები უნდა დაემატოს `messages_ka.properties`-ში: `user.name.notblank=სახელი სავალდებულოა.` --- ## 9.9 ლოკალიზაცია REST API-ებში REST API-ები არ იყენებენ თარგებს, ამიტომ საჭიროა `MessageSource`- ის პირდაპირი ინექცია: ```java @GetMapping("/greet") public String greet(Locale locale) { return messageSource.getMessage("greeting", null, locale); } ``` --- ## 9.11 თარიღების, რიცხვებისა და ვალუტის ფორმატირება ლოკალიზაცია მხოლოდ ტექსტის თარგმნა არაა. მაგალითად, აშშ-ში წერენ `$1,234.56`, ხოლო გერმანიაში `1.234,56 €`. Java-ში გამოიყენეთ `NumberFormat` ან `DateTimeFormatter`: ```java NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale); String price = currencyFormat.format(19.99); // "19,99 ₾" (ka-GE), "$19.99" (en-US) ``` --- ## 9.12 თარგმანების შენახვა მონაცემთა ბაზაში თუ გჭირდებათ თარგმანების მართვა აპლიკაციის გადატვირთვის გარეშე, შეგიძლიათ შექმნათ Custom `MessageSource`, რომელიც მონაცემებს `JdbcTemplate`-ით წაიკითხავს ბაზიდან. --- ## შეჯამება ეს თავი ფოკუსირებული იყო Spring Boot აპლიკაციის მრავალენოვნად ქცევაზე: * **Message bundles** ინახავს გარე ტექსტებს. * **LocaleResolver** განსაზღვრავს მომხმარებლის ენას (Cookie, Session, ან Header). * **LocaleChangeInterceptor** უზრუნველყოფს ენის შეცვლას URL პარამეტრით. * **Spring Macros** გვეხმარება FreeMarker-ში თარგმანების გამოტანაში. * **ლოკალზე დამოკიდებული ფორმატირება** უზრუნველყოფს რიცხვებისა და თარიღების სწორ ჩვენებას სხვადასხვა რეგიონისთვის.