בינלאומי ולוקליזציה בג'אווה 8

1. סקירה כללית

בינלאומי הוא תהליך של הכנת יישום לתמיכה בנתונים לשוניים, אזוריים, תרבותיים או פוליטיים ספציפיים. זהו היבט חיוני בכל יישום מודרני רב-שפות.

לקריאה נוספת, עלינו לדעת שיש קיצור פופולרי מאוד (כנראה פופולרי יותר מהשם האמיתי) לאינטרנציונליזציה - i18n בשל 18 האותיות שבין 'אני' ל- 'n'.

חשוב מאוד לתוכניות ארגוניות של ימינו לשרת אנשים ממקומות שונים בעולם או מאזורי תרבות מרובים. אזורי תרבות או שפה מובחנים לא רק קובעים תיאורים ספציפיים לשפה אלא גם מטבע, ייצוג מספרים ואפילו הרכב תאריך ושעה שונה.

למשל, בואו נתמקד במספרים ספציפיים למדינה. יש להם מספר עשרוני ואלף מפרידים שונים:

  • 102,300.45 (ארצות הברית)
  • 102 300,45 (פולין)
  • 102.300,45 (גרמניה)

ישנם פורמטים שונים של תאריכים גם כן:

  • יום שני, 1 בינואר, 2018 15:20:34 CET (ארצות הברית)
  • לונדי 1 ינואר 2018 15 שעות 20 CET (צרפת).
  • 2018 年 1 月 1 日 星期一 下午 03 时 20 分 34 秒 CET (סין)

יתרה מכך, במדינות שונות יש סמלי מטבע ייחודיים:

  • 1,200.60 ליש"ט (בריטניה)
  • € 1.200,60 (איטליה)
  • 1 200,60 € (צרפת)
  • 1,200,60 דולר (ארצות הברית)

עובדה חשובה לדעת היא שגם אם למדינות יש אותו מטבע וסמל מטבע - כמו צרפת ואיטליה - המיקום של סמל המטבע שלהן יכול להיות שונה.

2. לוקליזציה

בתוך ג'אווה, לרשותנו תכונה נהדרת הנקראת אזור מעמד.

זה מאפשר לנו להבדיל במהירות בין המקומות התרבותיים ולעצב את התוכן שלנו כראוי. זה חיוני בתהליך הבינלאומי. זהה ל- i18n, גם ללוקליזציה יש את הקיצור שלה - l10n.

הסיבה העיקרית לשימוש אזור הוא שניתן לגשת לכל העיצוב הספציפי למיקום הנדרש ללא קומפילציה מחדש. יישום יכול לטפל במקומות מרובים בו זמנית, כך שתמיכה בשפה חדשה היא פשוטה.

המקומות מיוצגים בדרך כלל על ידי שפה, מדינה וקיצור גרסאות המופרדים באמצעות קו תחתון:

  • דה (גרמנית)
  • it_CH (איטלקית, שוויץ)
  • en_US_UNIX (ארצות הברית, פלטפורמת UNIX)

2.1. שדות

כבר למדנו את זה אזור מורכב מקוד שפה, קוד מדינה וריאציה. ישנם שני שדות אפשריים נוספים להגדרה: סקריפט והרחבות.

בואו נסתכל ברשימת שדות ונראה מהם הכללים:

  • שפה יכול להיות ISO 639 אלפא -2 או אלפא -3 קוד או תג משנה של שפה רשומה.
  • אזור (מדינה) היא ISO 3166 אלפא -2 קוד מדינה או מספר 3 של האו"ם מיקוד.
  • גִרְסָה אַחֶרֶת הוא ערך תלוי רישיות או קבוצת ערכים המציינת וריאציה של a אזור.
  • תַסרִיט חייב להיות תקף ISO 15924 אלפא -4 קוד.
  • הרחבות היא מפה שמורכבת ממפתחות תווים בודדים ו חוּט ערכים.

רישום תגי המשנה של IANA מכיל ערכים אפשריים עבור שפה, אזור, גִרְסָה אַחֶרֶת ו תַסרִיט.

אין רשימה אפשרית סיומת ערכים, אך הערכים חייבים להיות מעוצבים היטב BCP-47 תגי משנה. המקשים והערכים מומרים תמיד באותיות קטנות.

2.2. אזור. בונה

ישנן מספר דרכים ליצור אזור חפצים. דרך אחת אפשרית מנצלת אזור. בונה. אזור. בונה יש לה חמש שיטות קובעות בהן אנו יכולים לבנות את האובייקט ובמקביל לאמת ערכים אלה:

אזור מקומי = Locale.Builder חדש () .setLanguage ("fr") .setRegion ("CA") .setVariant ("POSIX") .setScript ("Latn") .build ();

ה חוּט ייצוג של האמור לעיל אזור הוא fr_CA_POSIX_ # Latn.

טוב לדעת את זה הגדרת 'וריאנט' עשויה להיות מעט מסובכת מכיוון שאין הגבלה רשמית על ערכי גרסאות, אם כי שיטת הקובע דורשת זאת BCP-47 תואם.

אחרת, זה יזרוק חריגה לא פורמלית.

במקרה בו עלינו להשתמש בערך שאינו עובר אימות, אנו יכולים להשתמש בו אזור בונים מכיוון שהם אינם מאמתים ערכים.

2.3. קונסטרוקטורים

אזור בעל שלושה בונים:

  • אזור חדש (שפת מחרוזת)
  • אזור חדש (שפת מחרוזת, ארץ מחרוזת)
  • אזור חדש (שפת מחרוזת, ארץ מחרוזת, גרסת מחרוזת)

קונסטרוקטור בן 3 פרמטרים:

אזור מקומי = אזור חדש ("pl", "PL", "UNIX");

תקף גִרְסָה אַחֶרֶת חייב להיות חוּט של 5 עד 8 אלפא-נומריות או מספרית בודדת ואחריה 3 אלפא-נומריות. אנו יכולים להחיל את "UNIX" רק על ה- גִרְסָה אַחֶרֶת שדה רק באמצעות קונסטרוקטור מכיוון שהוא אינו עומד בדרישות אלה.

עם זאת, יש חסרון אחד בשימוש בבונים ליצירה אזור אובייקטים - איננו יכולים להגדיר סיומות ושדות סקריפט.

2.4. קבועים

זו כנראה הדרך הפשוטה והמצומצמת ביותר להשיג מקומיים. ה אזור בכיתה יש מספר קבועים סטטיים המייצגים את המדינה או השפה הפופולריים ביותר:

מקומי יפן = מקומי. JAPAN; מקומי יפני = מקומי. יפני;

2.5. תגי שפה

דרך נוספת ליצור אזור קורא לשיטת המפעל הסטטי forLanguageTag (שפת מחרוזת תג). שיטה זו דורשת א חוּט שעונה על IETF BCP 47 תֶקֶן.

כך אנו יכולים ליצור את בריטניה אזור:

Locale uk = Locale.forLanguageTag ("en-UK");

2.6. מקומות זמינים

למרות שנוכל ליצור שילובים מרובים של אזור אובייקטים, ייתכן שלא נוכל להשתמש בהם.

הערה חשובה שצריך להיות מודע אליה היא שה- מקומיים בפלטפורמה תלויים באלה שהותקנו בתוך זמן הריצה של Java.

כפי שאנו משתמשים מקומיים לעיצוב, המעצבים השונים עשויים להכיל קבוצה קטנה עוד יותר של מקומיים זמינים המותקנים ב- Runtime.

בואו לבדוק כיצד ניתן להשיג מערכים של מקומות זמינים:

אזור [] numberFormatLocales = NumberFormat.getAvailableLocales (); אזור [] dateFormatLocales = DateFormat.getAvailableLocales (); מקום [] locales = Locale.getAvailableLocales ();

לאחר מכן, אנו יכולים לבדוק האם שלנו אזור מתגורר בין זמינים מקומיים.

עלינו לזכור זאת מערך המקומות הזמינים שונה עבור יישומים שונים של פלטפורמת Javaותחומי פונקציונליות שונים.

הרשימה המלאה של האזורים הנתמכים זמינה בדף האינטרנט של ערכת הפיתוח של Java SE.

2.7. אזור ברירת מחדל

תוך כדי עבודה עם לוקליזציה, ייתכן שנצטרך לדעת מה ברירת המחדל אזור על שלנו JVM מופע הוא. למרבה המזל, יש דרך פשוטה לעשות זאת:

Locale defaultLocale = Locale.getDefault ();

כמו כן, אנו יכולים לציין ברירת מחדל אזור על ידי קריאה לשיטת מגדיר דומה:

Locale.setDefault (Locale.CANADA_FRENCH);

זה רלוונטי במיוחד כאשר נרצה ליצור JUnit בדיקות שאינן תלויות ב- JVM למשל.

3. מספרים ומטבעות

סעיף זה מתייחס למעצבי מספרים ומטבעות שצריכים להתאים למוסכמות שונות ספציפיות לאזור.

לעיצוב סוגי מספרים פרימיטיביים (int, לְהַכפִּיל) כמו גם מקבלי האובייקטים שלהם (מספר שלם, לְהַכפִּיל), עלינו להשתמש מספר פורמט המעמד ושיטות המפעל הסטטיות שלו.

שתי שיטות מעניינות אותנו:

  • NumberFormat.getInstance (אזור מקומי)
  • NumberFormat.getCurrencyInstance (אזור מקומי)

בואו נבחן קוד לדוגמא:

Locale usLocale = Locale.US; מספר כפול = 102300.456d; NumberFormat usNumberFormat = NumberFormat.getInstance (usLocale); assertEquals (usNumberFormat.format (number), "102,300.456");

כפי שאנחנו יכולים לראות זה פשוט כמו ליצור אזור ומשתמשים בו לאחזור מספר פורמט מופע ועיצוב מספר לדוגמא. אנו יכולים להבחין בכך הפלט כולל עשרוני ספציפי למיקום ואלף מפרידים.

הנה דוגמה נוספת:

Locale usLocale = Locale.US; מספר BigDecimal = BigDecimal חדש (102_300.456d); NumberFormat usNumberFormat = NumberFormat.getCurrencyInstance (usLocale); assertEquals (usNumberFormat.format (מספר), "$ 102,300.46");

עיצוב מטבע כולל את אותם השלבים כמו עיצוב מספר. ההבדל היחיד הוא שהמעצב מוסיף סמל מטבע וחלק עשרוני לשתי ספרות.

4. תאריך ושעה

עכשיו נלמד על עיצוב תאריכים ושעות שהוא כנראה מורכב יותר ממספרי עיצוב.

ראשית, עלינו לדעת כי עיצוב התאריך והשעה השתנה משמעותית ב- Java 8 מכיוון שהוא מכיל חדש לחלוטין תאריך שעה ממשק API. לכן אנו נבחן שיעורי עיצוב שונים.

4.1. DateTimeFormatter

מאז שהוצגה Java 8, המחלקה העיקרית לאיתור תאריכים ושעות היא DateTimeFormatter מעמד. הוא פועל על שיעורים המיישמים TemporalAccessor ממשק, למשל, LocalDateTime, LocalDate, LocalTime אוֹ ZonedDateTime. ליצור DateTimeFormatter עלינו לספק לפחות תבנית ואז אזור. בואו נראה קוד לדוגמא:

Locale.setDefault (Locale.US); LocalDateTime localDateTime = LocalDateTime.of (2018, 1, 1, 10, 15, 50, 500); דפוס מחרוזת = "dd-MMMM-yyyy HH: mm: ss.SSS"; DateTimeFormatter defaultTimeFormatter = DateTimeFormatter.ofPattern (תבנית); DateTimeFormatter deTimeFormatter = DateTimeFormatter.ofPattern (תבנית, אזור.גרמניה); assertEquals ("01 בינואר 2018 10: 15: 50.000", defaultTimeFormatter.format (localDateTime)); assertEquals ("01-ינואר-2018 10: 15: 50.000", deTimeFormatter.format (localDateTime));

אנו יכולים לראות זאת לאחר החזרה DateTimeFormatter כל שעלינו לעשות הוא להתקשר ל פוּרמָט() שיטה.

להבנה טובה יותר, עלינו להכיר אותיות דפוס אפשריות.

בואו נסתכל על אותיות למשל:

משמעות סמלים דוגמאות להצגה ------ ------- ------------ ------- y שנת עידן שנת 2004; 04 חודש / שנה מספר שנה / טקסט 7; 07; יול; יולי; J d יום בחודש מספר 10 H שעה ביום (0-23) מספר 0 מ 'דקה שעה מספר 30 שניות דקה שנייה 55 S שבריר שנייה 978

ניתן למצוא את כל אותיות הדפוס האפשריות עם הסבר בתיעוד Java של DateTimeFormatter.כדאי לדעת שהערך הסופי תלוי במספר הסמלים. בדוגמה יש 'MMMM' שמדפיס את שם החודש המלא ואילו אות 'M' אחת תיתן את מספר החודש ללא 0 מוביל.

לסיים הלאה DateTimeFormatterבואו נראה איך נוכל לעצב LocalizedDateTime:

LocalDateTime localDateTime = LocalDateTime.of (2018, 1, 1, 10, 15, 50, 500); ZoneId losAngelesTimeZone = TimeZone.getTimeZone ("אמריקה / Los_Angeles"). ToZoneId (); DateTimeFormatter localizedTimeFormatter = DateTimeFormatter .ofLocalizedDateTime (FormatStyle.FULL); מחרוזת formattedLocalizedTime = localizedTimeFormatter.format (ZonedDateTime.of (localDateTime, losAngelesTimeZone)); assertEquals ("יום שני, 1 בינואר, 2018 10:15:50 PST", formatLocalizedTime);

על מנת לעצב LocalizedDateTime, אנחנו יכולים להשתמש ב- ofLocalizedDateTime (FormatStyle dateTimeStyle) שיטה ולספק הגדרה מראש FormatStyle.

לעיון מעמיק יותר ב- Java 8 תאריך שעה API, יש לנו מאמר קיים כאן.

4.2. פורמט תאריך ו SimpleDateFormatter

מכיוון שעדיין מקובל לעבוד על פרויקטים המשתמשים בהם תאריכים ו לוחות שנה, נציג בקצרה יכולות עיצוב תאריכים ושעות עם פורמט תאריך ו SimpleDateFormat שיעורים.

בואו ננתח את היכולות של הראשונה:

GregorianCalendar gregorianCalendar = GregorianCalendar חדש (2018, 1, 1, 10, 15, 20); תאריך תאריך = gregorianCalendar.getTime (); DateFormat ffInstance = DateFormat.getDateTimeInstance (DateFormat.FULL, DateFormat.FULL, Locale.ITALY); DateFormat smInstance = DateFormat.getDateTimeInstance (DateFormat.SHORT, DateFormat.MEDIUM, Locale.ITALY); assertEquals ("giovedì 1 febbraio 2018 10.15.20 CET", ffInstance.format (תאריך)); assertEquals ("01/02/18 10.15.20", smInstance.format (תאריך));

פורמט תאריך עובד עם תאריכים ויש לו שלוש שיטות שימושיות:

  • getDateTimeInstance
  • getDateInstance
  • getTimeInstance

כולם לוקחים ערכים מוגדרים מראש של פורמט תאריך כפרמטר. כל שיטה עמוסה מדי, כל כך עוברת אזור אפשרי גם כן. אם אנו רוצים להשתמש בתבנית מותאמת אישית, כפי שהיא מתבצעת ב DateTimeFormatter, אנחנו יכולים להשתמש SimpleDateFormat. בוא נראה קטע קוד קצר:

GregorianCalendar gregorianCalendar = GregorianCalendar חדש (2018, 1, 1, 10, 15, 20); תאריך תאריך = gregorianCalendar.getTime (); Locale.setDefault (אזור חדש ("pl", "PL")); SimpleDateFormat fullMonthDateFormat = חדש SimpleDateFormat ("dd-MMMM-yyyy HH: mm: ss: SSS"); SimpleDateFormat shortMonthsimpleDateFormat = SimpleDateFormat חדש ("dd-MM-yyyy HH: mm: ss: SSS"); assertEquals ("01-lutego-2018 10: 15: 20: 000", fullMonthDateFormat.format (תאריך)); assertEquals ("01-02-2018 10: 15: 20: 000", shortMonthsimpleDateFormat.format (תאריך));

5. התאמה אישית

בשל כמה החלטות עיצוב טובות, איננו קשורים לתבנית עיצוב ספציפית למיקום, ואנו יכולים להגדיר כמעט כל פרט כך שיהיה מרוצה לחלוטין מפלט.

כדי להתאים אישית את עיצוב המספר, נוכל להשתמש פורמט עשרוני ו DecimalFormatSymbols.

הבה נבחן דוגמה קצרה:

Locale.setDefault (Locale.FRANCE); מספר BigDecimal = BigDecimal חדש (102_300.456d); DecimalFormat zeroDecimalFormat = חדש DecimalFormat ("000000000.0000"); DecimalFormat dollarDecimalFormat = DecimalFormat חדש ("$ ###, ###. ##"); assertEquals (zeroDecimalFormat.format (number), "000102300,4560"); assertEquals (dollarDecimalFormat.format (מספר), "$ 102 300,46"); 

ה פורמט עשרוני תיעוד מציג את כל תווי הדפוס האפשריים. כל שעלינו לדעת כעת הוא ש- "000000000.000" קובע אפסים מובילים או נגררים, ',' הוא אלף מפריד ו '.' הוא עשרוני.

אפשר גם להוסיף סמל מטבע. אנו יכולים לראות להלן שניתן להשיג את אותה תוצאה באמצעות DateFormatSymbol מעמד:

Locale.setDefault (Locale.FRANCE); מספר BigDecimal = BigDecimal חדש (102_300.456d); DecimalFormatSymbols decimalFormatSymbols = DecimalFormatSymbols.getInstance (); decimalFormatSymbols.setGroupingSeparator ('^'); decimalFormatSymbols.setDecimalSeparator ('@'); מפרידי DecimalFormatDecimalFormat = DecimalFormat חדש ("$ ###, ###. ##"); separatorsDecimalFormat.setGroupingSize (4); separatorsDecimalFormat.setCurrency (Currency.getInstance (Locale.JAPAN)); separatorsDecimalFormat.setDecimalFormatSymbols (decimalFormatSymbols); assertEquals (separatorsDecimalFormat.format (מספר), "$ 10 ^ [מוגן בדוא"ל]");

כמו שאנו יכולים לראות, DecimalFormatSymbols המחלקה מאפשרת לנו לציין כל עיצוב מספרים שנדמיין.

להתאמה אישית SimpleDataFormat, אנחנו יכולים להשתמש DateFormatSymbols.

בואו נראה כמה פשוט שינוי של שמות הימים:

תאריך תאריך = לוח שנה גרגוריאני חדש (2018, 1, 1, 10, 15, 20) .getTime (); Locale.setDefault (אזור חדש ("pl", "PL")); DateFormatSymbols dateFormatSymbols = חדש DateFormatSymbols (); dateFormatSymbols.setWeekdays (מחרוזת חדשה [] {"A", "B", "C", "D", "E", "F", "G", "H"}); SimpleDateFormat newDaysDateFormat = חדש SimpleDateFormat ("EEEE-MMMM-yyyy HH: mm: ss: SSS", dateFormatSymbols); assertEquals ("F-lutego-2018 10: 15: 20: 000", newDaysDateFormat.format (תאריך));

6. חבילות משאבים

לבסוף, החלק המכריע של הבינלאומיות ב JVM האם ה צרור משאבים מַנגָנוֹן.

מטרת א ResourceBundle זה לספק יישום עם הודעות / תיאורים מקומיים שניתן להחצין לקבצים הנפרדים. אנו מכסים את השימוש והתצורה של חבורת המשאבים באחד מהמאמרים הקודמים שלנו - מדריך לחבילת המשאבים.

7. מסקנה

מקומיים והמעצבים המשתמשים בהם הם כלים המסייעים לנו ליצור יישום בינלאומי. כלים אלה מאפשרים לנו ליצור יישום אשר יכול להסתגל באופן דינמי להגדרות הלשוניות או התרבותיות של המשתמש ללא מבנים מרובים או אפילו צורך לדאוג אם Java תומכת ב אזור.

בעולם שבו משתמש יכול להיות בכל מקום ולדבר בכל שפה, היכולת ליישם שינויים אלה פירושה שהיישומים שלנו יכולים להיות אינטואיטיביים ומובנים יותר על ידי משתמשים רבים יותר ברחבי העולם.

כשעובדים עם יישומי Spring Boot, יש לנו גם מאמר נוח לאינטרנציונליזציה של Spring Boot.

קוד המקור של הדרכה זו, עם דוגמאות מלאות, ניתן למצוא באתר GitHub.


$config[zx-auto] not found$config[zx-overlay] not found