--- a/usr/src/cmd/text-install/osol_install/text_install/Makefile Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/Makefile Wed Aug 11 15:34:19 2010 +0900
@@ -45,6 +45,7 @@
error_window.py \
fdisk_partitions.py \
help_screen.py \
+ i18n.py \
inner_window.py \
install_progress.py \
install_status.py \
--- a/usr/src/cmd/text-install/osol_install/text_install/__init__.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/__init__.py Wed Aug 11 15:34:19 2010 +0900
@@ -39,7 +39,7 @@
from os import environ
_ = gettext.translation("textinstall", "/usr/share/locale",
- fallback=True).gettext
+ fallback=True).ugettext
LOG_LOCATION_FINAL = "/var/sadm/system/logs/install_log"
DEFAULT_LOG_LOCATION = "/tmp/install_log"
DEFAULT_LOG_LEVEL = "info"
--- a/usr/src/cmd/text-install/osol_install/text_install/base_screen.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/base_screen.py Wed Aug 11 15:34:19 2010 +0900
@@ -156,7 +156,7 @@
self.on_continue()
except UIMessage as msg:
self.main_win.screen_list.previous_screen()
- error_str = str(msg)
+ error_str = unicode(msg)
if error_str:
self.main_win.error_line.display_err(error_str)
elif next_screen is None:
--- a/usr/src/cmd/text-install/osol_install/text_install/disk_selection.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/disk_selection.py Wed Aug 11 15:34:19 2010 +0900
@@ -40,6 +40,9 @@
from osol_install.text_install.disk_window import DiskWindow, \
get_minimum_size, \
get_recommended_size
+from osol_install.text_install.i18n import fit_text_truncate, \
+ textwidth, \
+ ljust_columns
from osol_install.text_install.list_item import ListItem
from osol_install.text_install.scroll_window import ScrollWindow
from osol_install.text_install.window_area import WindowArea
@@ -106,8 +109,7 @@
disk_header_text = []
for header in DiskScreen.DISK_HEADERS:
- header_str = header[1][:header[0]-1]
- header_str = header_str.ljust(header[0]-1)
+ header_str = fit_text_truncate(header[1], header[0]-1, just="left")
disk_header_text.append(header_str)
self.disk_header_text = " ".join(disk_header_text)
max_note_size = DiskScreen.DISK_HEADERS[5][0]
@@ -179,7 +181,7 @@
self.center_win.add_text(DiskScreen.DISK_SEEK_TEXT, 5, 1,
self.win_size_x - 3)
self.main_win.do_update()
- offset = len(DiskScreen.DISK_SEEK_TEXT) + 2
+ offset = textwidth(DiskScreen.DISK_SEEK_TEXT) + 2
spin_index = 0
self.center_win.window.timeout(250)
while self.td_handle.is_alive():
@@ -262,10 +264,11 @@
y_loc += 1
self.center_win.window.hline(y_loc, self.center_win.border_size[1] + 1,
curses.ACS_HLINE,
- len(self.disk_header_text))
+ textwidth(self.disk_header_text))
y_loc += 1
- disk_win_area = WindowArea(4, len(self.disk_header_text) + 2, y_loc, 0)
+ disk_win_area = WindowArea(4, textwidth(self.disk_header_text) + 2,
+ y_loc, 0)
disk_win_area.scrollable_lines = len(self.disks) + 1
self.disk_win = ScrollWindow(disk_win_area,
window=self.center_win)
@@ -280,7 +283,7 @@
for disk in self.disks:
disk_text_fields = []
type_field = disk.type[:len_type]
- type_field = type_field.ljust(len_type)
+ type_field = ljust_columns(type_field, len_type)
disk_text_fields.append(type_field)
disk_size = disk.size.size_as("gb")
size_field = "%*.1f" % (len_size, disk_size)
@@ -291,11 +294,11 @@
bootable_field = " " * (len_boot)
disk_text_fields.append(bootable_field)
device_field = disk.name[:len_dev]
- device_field = device_field.ljust(len_dev)
+ device_field = ljust_columns(device_field, len_dev)
disk_text_fields.append(device_field)
if disk.vendor is not None:
mftr_field = disk.vendor[:len_mftr]
- mftr_field = mftr_field.ljust(len_mftr)
+ mftr_field = ljust_columns(mftr_field, len_mftr)
else:
mftr_field = " " * len_mftr
disk_text_fields.append(mftr_field)
--- a/usr/src/cmd/text-install/osol_install/text_install/disk_window.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/disk_window.py Wed Aug 11 15:34:19 2010 +0900
@@ -36,6 +36,7 @@
from osol_install.text_install import _, LOG_LEVEL_INPUT
from osol_install.text_install.base_screen import UIMessage
from osol_install.text_install.edit_field import EditField
+from osol_install.text_install.i18n import fit_text_truncate, textwidth
from osol_install.text_install.inner_window import InnerWindow, no_action
from osol_install.text_install.list_item import ListItem
from osol_install.text_install.scroll_window import ScrollWindow
@@ -225,12 +226,12 @@
right_header_str = header[2]
# Trim the header to fit in the column width,
# splitting columns with at least 1 space
- left_header_str = left_header_str[:header[0]-1]
- right_header_str = right_header_str[:header[0]-1]
# Pad with extra space(s) to align the columns
- left_header_str = left_header_str.ljust(header[0]-1)
- right_header_str = right_header_str.ljust(header[0]-1)
+ left_header_str = fit_text_truncate(left_header_str,
+ header[0]-1, just="left")
self.left_header_string.append(left_header_str)
+ right_header_str = fit_text_truncate(right_header_str,
+ header[0]-1, just="left")
self.right_header_string.append(right_header_str)
self.left_header_string = " ".join(self.left_header_string)
self.right_header_string = " ".join(self.right_header_string)
@@ -240,9 +241,9 @@
DiskWindow.SCROLL_PAD)
self.add_text(self.right_header_string, 0, right_win_offset)
self.window.hline(1, DiskWindow.SCROLL_PAD, curses.ACS_HLINE,
- len(self.left_header_string))
+ textwidth(self.left_header_string))
self.window.hline(1, right_win_offset, curses.ACS_HLINE,
- len(self.right_header_string))
+ textwidth(self.right_header_string))
self.no_ut_refresh()
def print_data(self):
--- a/usr/src/cmd/text-install/osol_install/text_install/edit_field.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/edit_field.py Wed Aug 11 15:34:19 2010 +0900
@@ -31,6 +31,7 @@
from curses.ascii import isprint, ctrl, ismeta
from osol_install.text_install.base_screen import UIMessage
+from osol_install.text_install.i18n import rjust_columns
from osol_install.text_install.inner_window import InnerWindow, consume_action
@@ -197,7 +198,7 @@
width = self.area.columns - 1
if text:
text = text.lstrip(self.numeric_pad)
- text = text.rjust(width, self.numeric_pad)
+ text = rjust_columns(text, width, self.numeric_pad)
self._set_text(text)
def _set_text(self, text):
@@ -352,7 +353,7 @@
self.validate(self, **self.validate_kwargs)
except UIMessage as error_str:
if self.error_win is not None:
- self.error_win.display_err(str(error_str))
+ self.error_win.display_err(unicode(error_str))
return False
if self.error_win is not None and self.error_win.visible:
self.error_win.clear_err()
@@ -371,7 +372,7 @@
return True
except UIMessage as error_str:
if self.error_win is not None:
- self.error_win.display_err(str(error_str))
+ self.error_win.display_err(unicode(error_str))
return False
return True
--- a/usr/src/cmd/text-install/osol_install/text_install/fdisk_partitions.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/fdisk_partitions.py Wed Aug 11 15:34:19 2010 +0900
@@ -30,6 +30,7 @@
from osol_install.text_install.base_screen import BaseScreen, SkipException
from osol_install.text_install.disk_window import DiskWindow
+from osol_install.text_install.i18n import textwidth
from osol_install.text_install.list_item import ListItem
from osol_install.text_install.window_area import WindowArea
from osol_install.text_install import _
@@ -164,7 +165,7 @@
y_loc += disk_win_area.lines
y_loc += 3
- whole_disk_width = len(self.use_whole) + 3
+ whole_disk_width = textwidth(self.use_whole) + 3
cols = (self.win_size_x - whole_disk_width) / 2
whole_disk_item_area = WindowArea(1, whole_disk_width, y_loc, cols)
self.whole_disk_item = ListItem(whole_disk_item_area,
@@ -173,7 +174,7 @@
centered=True)
y_loc += 1
- partial_width = len(self.use_part) + 3
+ partial_width = textwidth(self.use_part) + 3
cols = (self.win_size_x - partial_width) / 2
partial_item_area = WindowArea(1, partial_width, y_loc, cols)
self.partial_disk_item = ListItem(partial_item_area,
--- a/usr/src/cmd/text-install/osol_install/text_install/help_screen.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/help_screen.py Wed Aug 11 15:34:19 2010 +0900
@@ -35,7 +35,7 @@
from osol_install.text_install import _
from osol_install.text_install.action import Action
from osol_install.text_install.base_screen import BaseScreen
-from osol_install.text_install.inner_window import InnerWindow
+from osol_install.text_install.i18n import convert_paragraph, textwidth
from osol_install.text_install.list_item import ListItem
from osol_install.text_install.scroll_window import ScrollWindow
from osol_install.text_install.window_area import WindowArea
@@ -194,7 +194,7 @@
topic_format = info[1]
help_topic = self.get_help_topic(info[0])
help_topic = topic_format % help_topic
- hilite = min(self.win_size_x, len(help_topic) + 1)
+ hilite = min(self.win_size_x, textwidth(help_topic) + 1)
list_item = ListItem(WindowArea(1, hilite, idx, 0),
window=self.scroll_region, text=help_topic)
help_screens = info[0]
@@ -247,8 +247,7 @@
self.main_win.set_header_text(help_header)
- help_text = InnerWindow.convert_paragraph(help_text,
- self.win_size_x - 5)
+ help_text = convert_paragraph(help_text, self.win_size_x - 5)
logging.debug("help_text #lines=%d, text is \n%s",
len(help_text), help_text)
area = WindowArea(x_loc=0, y_loc=1,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/i18n.py Wed Aug 11 15:34:19 2010 +0900
@@ -0,0 +1,197 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+''' methods for internationalized text processing, which
+counts "columns" in applicable cases, rather than assuming
+columns are same as characters or bytes.
+
+'''
+
+import locale
+from unicodedata import east_asian_width
+from osol_install.text_install import _
+
+# for specifying justification in fit_text_truncate()
+LEFT = "left"
+RIGHT = "right"
+CENTER = "center"
+
+def get_encoding():
+ ''' Get encoding of current locale
+ '''
+ enc = locale.getlocale(locale.LC_CTYPE)[1]
+ if enc is None:
+ enc = locale.getpreferredencoding()
+
+ return enc
+
+def charwidth(c):
+ ''' Count column width needed for given Unicode character
+ '''
+ if isinstance(c, str):
+ c = c.decode(get_encoding())
+ width_class = east_asian_width(c)
+
+ if width_class == "F" or width_class == "W":
+ return 2
+ else:
+ return 1
+
+def textwidth(text):
+ ''' Count column width needed for given string.
+ '''
+ if isinstance(text, str):
+ text = text.decode(get_encoding())
+ text = text.expandtabs(4)
+
+ width_total = 0
+
+ for char in text:
+ width_total += charwidth(char)
+
+ return width_total
+
+def if_wrap_on_whitespace():
+ ''' Get information on whether wrapping text should be done on
+ white space or on arbitrary position. Default is True as in English.
+ '''
+ val = _("DONT_TRANSLATE_BUT_REPLACE_msgstr_WITH_True_OR_False: "
+ "Should wrap text on whitespace in this language")
+
+ if val == "False":
+ return False
+ else:
+ return True
+
+def fit_text_truncate(text, max_width, just="", fillchar=u" "):
+ ''' Fit a text in max_width columns, by truncating the text if needed.
+ If just is one of LEFT, RIGHT, or CENTER, justify text
+ and fill unused room with fillchar.
+ '''
+ if isinstance(text, str):
+ text = text.decode(get_encoding())
+
+ text = text.expandtabs(4)
+
+ if fillchar is None:
+ fillchar = u" "
+ if isinstance(fillchar, str):
+ fillchar = fillchar.decode(get_encoding())
+ if charwidth(fillchar) != 1:
+ raise ValueError('Cannot use multi-column character "%c" as '
+ 'fillchar.' % fillchar)
+
+ fitted_text = u""
+ width_total = 0
+
+ for char in text:
+ width = charwidth(char)
+ if width_total + width > max_width:
+ break
+ fitted_text += char
+ width_total += width
+
+ npad = max_width - width_total
+
+ if just and npad > 0:
+ if just == LEFT:
+ fitted_text = fitted_text + fillchar * npad
+ elif just == RIGHT:
+ fitted_text = fillchar * npad + fitted_text
+ elif just == CENTER:
+ nleft = npad // 2
+ nright = npad - nleft
+ fitted_text = fillchar * nleft + fitted_text + fillchar * nright
+ else:
+ raise ValueError("Unknown just=%s" % just)
+
+ return fitted_text
+
+def ljust_columns(text, max_width, fillchar=u" "):
+ ''' alternative to ljust(); counts multicolumn characters correctly
+ '''
+ return fit_text_truncate(text, max_width, just=LEFT, fillchar=fillchar)
+
+def rjust_columns(text, max_width, fillchar=u" "):
+ ''' alternative to rjust(); counts multicolumn characters correctly
+ '''
+ return fit_text_truncate(text, max_width, just=RIGHT, fillchar=fillchar)
+
+def center_columns(text, max_width, fillchar=u" "):
+ ''' alternative to center(); counts multicolumn characters correctly
+ '''
+ return fit_text_truncate(text, max_width, just=CENTER, fillchar=fillchar)
+
+def convert_paragraph(text, max_chars):
+ '''Break a paragraph of text up into chunks that will each
+ fit within max_chars. Splits on whitespace (if wrapping on
+ whitespace is used in current language) and newlines.
+
+ max_chars defaults to the size of this window.
+
+ '''
+ wrap_on_whitespace = if_wrap_on_whitespace()
+
+ if isinstance(text, str):
+ text = text.decode(get_encoding())
+
+ text_lines = text.expandtabs(4).splitlines()
+ paragraphed_lines = []
+
+ for line in text_lines:
+ width_total = 0
+ last_whitespace = None
+ width_upto_last_whitespace = None
+ start_pt = 0
+ for i, c in enumerate(line):
+ width = charwidth(c)
+ if width_total + width > max_chars:
+ if wrap_on_whitespace and last_whitespace is not None :
+ # put upto last white space
+ end_pt = last_whitespace + 1
+ paragraphed_lines.append(line[start_pt:end_pt].lstrip())
+ # next line will start at char next to the white space
+ start_pt = last_whitespace + 1
+ width_total -= width_upto_last_whitespace
+ # forget last white space
+ last_whitespace = None
+ width_upto_last_whitespace = None
+ else:
+ # white space didn't appear; put upto last char
+ end_pt = i
+ paragraphed_lines.append(line[start_pt:end_pt].lstrip())
+ # next line will start at current char
+ start_pt = i
+ width_total = 0
+ width_total += width
+ if c == u' ':
+ if i == start_pt:
+ # not count leading white space
+ width_total -= width
+ else:
+ last_whitespace = i
+ width_upto_last_whitespace = width_total
+ # flush last part of "line" (each item of text_lines)
+ paragraphed_lines.append(line[start_pt:].lstrip())
+ return paragraphed_lines
+
--- a/usr/src/cmd/text-install/osol_install/text_install/inner_window.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/inner_window.py Wed Aug 11 15:34:19 2010 +0900
@@ -34,7 +34,10 @@
from copy import copy
from osol_install.text_install import LOG_LEVEL_INPUT
-
+from osol_install.text_install.i18n import fit_text_truncate, \
+ convert_paragraph, \
+ get_encoding, \
+ textwidth
KEY_ESC = 27
KEY_BS = 127 # Backspace code that curses doesn't translate right
@@ -310,55 +313,30 @@
'''
win_y, win_x = self.window.getmaxyx()
- logging.log(LOG_LEVEL_INPUT, "start_y=%d, start_x=%d, max_chars=%s, centered=%s,"
- " win_max_x=%s, win_max_y=%s",
+ logging.log(LOG_LEVEL_INPUT, "start_y=%d, start_x=%d, max_chars=%s, "
+ "centered=%s, win_max_x=%s, win_max_y=%s",
start_y, start_x, max_chars, centered, win_x, win_y)
max_x = self.window.getmaxyx()[1] - self.border_size[1]
start_x += self.border_size[1]
- if centered:
- length = len(text)
- max_x = max_x - start_x
- if self.window.getmaxyx()[0] == (start_y + 1):
- max_x -= 1 # Cannot print to bottom-right corner
- start_x = max((max_x - length) / 2 + start_x, start_x)
abs_max_chars = max_x - start_x
if max_chars is None:
max_chars = abs_max_chars
else:
max_chars = min(max_chars, abs_max_chars)
-
- logging.log(LOG_LEVEL_INPUT, "calling addnstr with params start_y=%s, start_x=%s, "
- "text=%s, max_chars=%s", start_y, start_x, text, max_chars)
- self.window.addnstr(start_y, start_x, text, max_chars)
- self.no_ut_refresh()
-
- @staticmethod
- def convert_paragraph(text, max_chars):
- '''Break a paragraph of text up into chunks that will each
- fit within max_chars. Splits on whitespace and newlines
-
- max_chars defaults to the size of this window.
+
+ text = fit_text_truncate(text, max_chars)
+
+ if centered:
+ start_x = (max_x - textwidth(text)) / 2 + start_x
- '''
- text_lines = text.expandtabs(4).splitlines()
- paragraphed_lines = []
- for line in text_lines:
- if len(line) <= max_chars:
- paragraphed_lines.append(line)
- else:
- start_pt = 0
- end_pt = 0
- while end_pt + max_chars < len(line):
- end_pt = line.rfind(" ", start_pt, start_pt + max_chars)
- if end_pt == -1:
- end_pt = start_pt + max_chars
- paragraphed_lines.append(line[start_pt:end_pt].lstrip())
- start_pt = end_pt + 1
- else:
- paragraphed_lines.append(line[end_pt:].lstrip())
- return paragraphed_lines
-
+ if isinstance(text, unicode):
+ text = text.encode(get_encoding())
+ logging.log(LOG_LEVEL_INPUT, "calling addstr with params start_y=%s,"
+ "start_x=%s, text=%s", start_y, start_x, text)
+ self.window.addstr(start_y, start_x, text)
+ self.no_ut_refresh()
+
def add_paragraph(self, text, start_y=0, start_x=0, max_y=None,
max_x=None):
'''Add a block of text to the window
@@ -380,11 +358,13 @@
max_y = win_size_y - start_y - self.border_size[0]
if max_x is None:
max_x = win_size_x
- max_chars = max_x - start_x - self.border_size[1] - 1
+ max_chars = max_x - start_x - self.border_size[1] * 2
y_index = start_y
if isinstance(text, basestring):
- text = self.convert_paragraph(text, max_chars)
+ text = convert_paragraph(text, max_chars)
for line in text:
+ logging.log(LOG_LEVEL_INPUT, "add_paragraph:add_text: y_index=%d, "
+ "line=%s\n", y_index, line)
self.add_text(line, y_index, start_x, max_chars)
y_index += 1
if y_index > max_y + start_y:
--- a/usr/src/cmd/text-install/osol_install/text_install/install_progress.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/install_progress.py Wed Aug 11 15:34:19 2010 +0900
@@ -35,6 +35,7 @@
from osol_install.text_install import _, LOG_LEVEL_INPUT
from osol_install.text_install.base_screen import BaseScreen
+from osol_install.text_install.i18n import ljust_columns
from osol_install.text_install.inner_window import InnerWindow
from osol_install.text_install.window_area import WindowArea
from osol_install.text_install.ti_install import perform_ti_install
@@ -205,7 +206,7 @@
def set_status_message(self, message):
'''Set the status message on the screen, completely overwriting
the previous message'''
- self.center_win.add_text(message.ljust(self.status_msg_loc[2]),
+ self.center_win.add_text(ljust_columns(message, self.status_msg_loc[2]),
self.status_msg_loc[0],
self.status_msg_loc[1],
max_chars=self.status_msg_loc[2])
--- a/usr/src/cmd/text-install/osol_install/text_install/log_viewer.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/log_viewer.py Wed Aug 11 15:34:19 2010 +0900
@@ -30,7 +30,7 @@
from osol_install.text_install import _
from osol_install.text_install.base_screen import BaseScreen
-from osol_install.text_install.inner_window import InnerWindow
+from osol_install.text_install.i18n import convert_paragraph
from osol_install.text_install.scroll_window import ScrollWindow
from osol_install.text_install.window_area import WindowArea
@@ -79,5 +79,5 @@
if log_file is not None:
log_file.close()
max_chars = self.win_size_x - 4
- self.log_data = InnerWindow.convert_paragraph(log_data, max_chars)
+ self.log_data = convert_paragraph(log_data, max_chars)
return self.log_data
--- a/usr/src/cmd/text-install/osol_install/text_install/main_window.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/main_window.py Wed Aug 11 15:34:19 2010 +0900
@@ -34,6 +34,9 @@
from osol_install.text_install.color_theme import ColorTheme
from osol_install.text_install.action import Action
from osol_install.text_install.error_window import ErrorWindow
+from osol_install.text_install.i18n import textwidth, \
+ center_columns, \
+ get_encoding
from osol_install.text_install.inner_window import InnerWindow
from osol_install.text_install.list_item import ListItem
from osol_install.text_install.scroll_window import ScrollWindow
@@ -157,7 +160,7 @@
def set_header_text(self, header_text):
'''Set the header_text'''
- text = header_text.center(self.header.area.columns - 1)
+ text = center_columns(header_text, self.header.area.columns - 1)
self.header.add_text(text)
self._cur_header_text = text
@@ -193,12 +196,12 @@
strings.append(action_str)
display_str = "".join(strings)
max_len = self.footer.window.getmaxyx()[1]
- length = len(display_str)
+ length = textwidth(display_str)
if not InnerWindow.USE_ESC:
length += (len(" Esc-") - len(" F")) * len(self.actions)
if length > max_len:
raise ValueError("Can't display footer actions - string too long")
- self.footer.window.addstr(display_str)
+ self.footer.window.addstr(display_str.encode(get_encoding()))
self.footer.window.noutrefresh()
def getch(self):
@@ -250,7 +253,7 @@
# Add the header, a border, and the question to the window
self.popup_win.window.border()
- header_x = (self.popup_win.area.columns - len(header)) / 2
+ header_x = (self.popup_win.area.columns - textwidth(header)) / 2
self.popup_win.add_text(header, 0, header_x)
y_loc = 2
y_loc += self.popup_win.add_paragraph(question, y_loc, 2)
@@ -267,10 +270,10 @@
# Create two "buttons" of equal size by finding the larger of the
# two, and centering them
- max_len = max(len(left_btn_txt), len(right_btn_txt))
+ max_len = max(textwidth(left_btn_txt), textwidth(right_btn_txt))
left_btn_txt = " [ %s ]" % left_btn_txt.center(max_len)
right_btn_txt = " [ %s ]" % right_btn_txt.center(max_len)
- button_len = len(left_btn_txt) + 1
+ button_len = textwidth(left_btn_txt) + 1
win_size = self.popup_win.window.getmaxyx()
left_area = WindowArea(1, button_len, y_loc,
(win_size[1] / 2) - (button_len + 2))
--- a/usr/src/cmd/text-install/osol_install/text_install/network_type.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/network_type.py Wed Aug 11 15:34:19 2010 +0900
@@ -34,6 +34,7 @@
from osol_install.text_install import _
from osol_install.text_install.base_screen import BaseScreen, UIMessage
from osol_install.text_install.edit_field import EditField
+from osol_install.text_install.i18n import textwidth
from osol_install.text_install.list_item import ListItem
from osol_install.text_install.window_area import WindowArea
@@ -67,7 +68,7 @@
def __init__(self, main_win):
super(NetworkTypeScreen, self).__init__(main_win)
- self.hostfield_offset = len(NetworkTypeScreen.HOSTNAME_TEXT)
+ self.hostfield_offset = textwidth(NetworkTypeScreen.HOSTNAME_TEXT)
self.menu_item_desc_max = (self.win_size_x -
NetworkTypeScreen.ITEM_DESC_OFFSET)
--- a/usr/src/cmd/text-install/osol_install/text_install/partition_edit_screen.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/partition_edit_screen.py Wed Aug 11 15:34:19 2010 +0900
@@ -32,6 +32,7 @@
import platform
from osol_install.profile.disk_info import PartitionInfo, SliceInfo
+from osol_install.text_install import LOG_LEVEL_INPUT
from osol_install.text_install.action import Action
from osol_install.text_install.base_screen import BaseScreen, \
SkipException, \
@@ -172,7 +173,10 @@
reset=self.orig_data)
y_loc += disk_win_area.lines
- y_loc += 2
+ y_loc += 1
+ logging.log(LOG_LEVEL_INPUT, "calling addch with params start_y=%s,"
+ "start_x=%s, ch=%c", y_loc, self.center_win.border_size[1],
+ DiskWindow.DESTROYED_MARK)
self.center_win.window.addch(y_loc, self.center_win.border_size[1],
DiskWindow.DESTROYED_MARK,
self.center_win.color_theme.inactive)
--- a/usr/src/cmd/text-install/osol_install/text_install/summary.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/summary.py Wed Aug 11 15:34:19 2010 +0900
@@ -34,7 +34,7 @@
from osol_install.text_install import _
from osol_install.text_install.action import Action
from osol_install.text_install.base_screen import BaseScreen
-from osol_install.text_install.inner_window import InnerWindow
+from osol_install.text_install.i18n import convert_paragraph
from osol_install.text_install.window_area import WindowArea
from osol_install.text_install.scroll_window import ScrollWindow
@@ -70,7 +70,7 @@
# Wrap the summary text, accounting for the INDENT (used below in
# the call to add_paragraph)
max_chars = self.win_size_x - SummaryScreen.INDENT - 1
- summary_text = InnerWindow.convert_paragraph(summary_text, max_chars)
+ summary_text = convert_paragraph(summary_text, max_chars)
area = WindowArea(x_loc=0, y_loc=y_loc,
scrollable_lines=(len(summary_text)+1))
area.lines = self.win_size_y - y_loc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/text-install/osol_install/text_install/test/test_i18n.py Wed Aug 11 15:34:19 2010 +0900
@@ -0,0 +1,189 @@
+#!/usr/bin/python2.6
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''
+To run these tests:
+
+1) nightly -n developer.sh # build the gate
+2) export PYTHONPATH=${WS}/proto/root_i386/usr/snadm/lib:${WS}/proto/root_i386/usr/lib/python2.6/vendor-packages
+3) python2.6 test_i18n.py
+
+A single test may be run by specifying the test as an argument to step 3:
+python2.6 test_i18n.py I18nTestCase.test_charwidth
+
+Since the proto area is used for the PYTHONPATH, the gate must be rebuilt for
+these tests to pick up any changes in the tested code.
+
+'''
+
+import unittest
+import locale
+
+from osol_install.text_install.i18n import get_encoding, \
+ if_wrap_on_whitespace, \
+ charwidth, \
+ textwidth, \
+ fit_text_truncate, \
+ convert_paragraph, \
+ LEFT, \
+ RIGHT, \
+ CENTER
+
+class I18nTestCase(unittest.TestCase):
+ def setUp(self):
+ # save current locale
+ self.save_locale = locale.getlocale(locale.LC_ALL)
+ # set locale
+ locale.setlocale(locale.LC_ALL, "")
+ # if not in UTF-8 locale, fallback to en_US.UTF-8
+ enc = locale.getlocale(locale.LC_CTYPE)[1]
+ if enc is None or enc.upper() != "UTF-8" and enc.upper() != "UTF8":
+ print "This test script uses hard-coded Unicode characters and "
+ print "needs to run in a UTF-8 locale. Fallback to en_US.UTF-8."
+ locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
+
+ def tearDown(self):
+ # restore locale
+ locale.setlocale(locale.LC_ALL, self.save_locale)
+
+ def test_charwidth(self):
+ ''' test charwidth() '''
+ # example of 1-column character (ASCII)
+ self.assertEqual(charwidth(u'A'), 1)
+ self.assertEqual(charwidth(u'A'.encode(get_encoding())), 1)
+ # example of 1-column character (non-ASCII)
+ self.assertEqual(charwidth(u'\u00c0'), 1)
+ self.assertEqual(charwidth(u'\u00c0'.encode(get_encoding())), 1)
+ # example of 2-column character
+ self.assertEqual(charwidth(u'\u3042'), 2)
+ self.assertEqual(charwidth(u'\u3042'.encode(get_encoding())), 2)
+
+ def test_textwidth(self):
+ ''' test textwidth() '''
+ # without tab
+ self.assertEqual(textwidth(u'A\u00c0\u3042'), 1 + 1 + 2)
+ self.assertEqual(textwidth(u'A\u00c0\u3042'.encode(get_encoding())),
+ 1 + 1 + 2)
+ # with tab
+ self.assertEqual(textwidth(u'\tA\u00c0\u3042'), 4 + 1 + 1 + 2)
+ self.assertEqual(textwidth(u'\tA\u00c0\u3042'.encode(get_encoding())),
+ 4 + 1 + 1 + 2)
+
+ def test_fit_text_truncate(self):
+ ''' test fit_text_truncate() '''
+ c0 = u'\u3042' # 2 columns
+ c1 = u'\u3044' # 2 columns
+ c2 = u'\u3046' # 2 columns
+ c3 = u'\u3048' # 2 columns
+ s = c0 + c1 + c2 + c3
+ # no justification
+ self.assertEqual(fit_text_truncate(s, 9), s[:4])
+ self.assertEqual(fit_text_truncate(s, 8), s[:4])
+ self.assertEqual(fit_text_truncate(s, 7), s[:3])
+ self.assertEqual(fit_text_truncate(s, 6), s[:3])
+ self.assertEqual(fit_text_truncate(s, 5), s[:2])
+ self.assertEqual(fit_text_truncate(s, 4), s[:2])
+ self.assertEqual(fit_text_truncate(s, 3), s[:1])
+ self.assertEqual(fit_text_truncate(s, 2), s[:1])
+ self.assertEqual(fit_text_truncate(s, 1), s[:0])
+ self.assertEqual(fit_text_truncate(s, 0), s[:0])
+ # justify to left
+ self.assertEqual(fit_text_truncate(s, 9, just=LEFT), s[:4] + u' ')
+ self.assertEqual(fit_text_truncate(s, 8, just=LEFT), s[:4])
+ self.assertEqual(fit_text_truncate(s, 7, just=LEFT), s[:3] + u' ')
+ self.assertEqual(fit_text_truncate(s, 6, just=LEFT), s[:3])
+ self.assertEqual(fit_text_truncate(s, 5, just=LEFT), s[:2] + u' ')
+ self.assertEqual(fit_text_truncate(s, 4, just=LEFT), s[:2])
+ self.assertEqual(fit_text_truncate(s, 3, just=LEFT), s[:1] + u' ')
+ self.assertEqual(fit_text_truncate(s, 2, just=LEFT), s[:1])
+ self.assertEqual(fit_text_truncate(s, 1, just=LEFT), s[:0] + u' ')
+ self.assertEqual(fit_text_truncate(s, 0, just=LEFT), s[:0])
+ # justify to right
+ self.assertEqual(fit_text_truncate(s, 9, just=RIGHT), u' ' + s[:4])
+ self.assertEqual(fit_text_truncate(s, 8, just=RIGHT), s[:4])
+ self.assertEqual(fit_text_truncate(s, 7, just=RIGHT), u' ' + s[:3])
+ self.assertEqual(fit_text_truncate(s, 6, just=RIGHT), s[:3])
+ self.assertEqual(fit_text_truncate(s, 5, just=RIGHT), u' ' + s[:2])
+ self.assertEqual(fit_text_truncate(s, 4, just=RIGHT), s[:2])
+ self.assertEqual(fit_text_truncate(s, 3, just=RIGHT), u' ' + s[:1])
+ self.assertEqual(fit_text_truncate(s, 2, just=RIGHT), s[:1])
+ self.assertEqual(fit_text_truncate(s, 1, just=RIGHT), u' ' + s[:0])
+ self.assertEqual(fit_text_truncate(s, 0, just=RIGHT), s[:0])
+ # justify to center
+ self.assertEqual(fit_text_truncate(s, 12, just=CENTER),
+ u' ' * 2 + s[:4] + u' ' * 2)
+ self.assertEqual(fit_text_truncate(s, 11, just=CENTER),
+ u' ' + s[:4] + u' ' * 2)
+ self.assertEqual(fit_text_truncate(s, 10, just=CENTER),
+ u' ' + s[:4] + u' ')
+ self.assertEqual(fit_text_truncate(s, 9, just=CENTER), s[:4] + u' ')
+ self.assertEqual(fit_text_truncate(s, 8, just=CENTER), s[:4])
+ self.assertEqual(fit_text_truncate(s, 7, just=CENTER), s[:3] + u' ')
+ self.assertEqual(fit_text_truncate(s, 6, just=CENTER), s[:3])
+ self.assertEqual(fit_text_truncate(s, 5, just=CENTER), s[:2] + u' ')
+ self.assertEqual(fit_text_truncate(s, 4, just=CENTER), s[:2])
+ self.assertEqual(fit_text_truncate(s, 3, just=CENTER), s[:1] + u' ')
+ self.assertEqual(fit_text_truncate(s, 2, just=CENTER), s[:1])
+ self.assertEqual(fit_text_truncate(s, 1, just=CENTER), s[:0] + u' ')
+ self.assertEqual(fit_text_truncate(s, 0, just=CENTER), s[:0])
+
+ def test_fit_text_truncate_multicolumn_fillchar(self):
+ ''' test fit_text_truncate() with specifying multicolumn fillchar,
+ expecting ValueError is raised
+ '''
+ self.assertRaises(ValueError, fit_text_truncate,
+ u"\u3042", 9, just=LEFT, fillchar=u'\u3042')
+ self.assertRaises(ValueError, fit_text_truncate,
+ u"\u3042", 9, just=RIGHT, fillchar=u'\u3042')
+ self.assertRaises(ValueError, fit_text_truncate,
+ u"\u3042", 9, just=CENTER, fillchar=u'\u3042')
+
+ def test_convert_paragraph(self):
+ ''' test convert_paragraph() '''
+ c0 = u'\u3042' # 2 columns
+ c1 = u'\u3044' # 2 columns
+ c2 = u' ' # 1 column (white space)
+ c3 = u'\u3046' # 2 columns
+ c4 = u'\u3048' # 2 columns
+ s = c0 + c1 + c2 + c3 + c4
+
+ if if_wrap_on_whitespace():
+ self.assertEqual(convert_paragraph(s, 10), [s])
+ self.assertEqual(convert_paragraph(s, 9), [s])
+ self.assertEqual(convert_paragraph(s, 8), [s[:3], s[3:].lstrip()])
+ self.assertEqual(convert_paragraph(s, 7), [s[:3], s[3:].lstrip()])
+ self.assertEqual(convert_paragraph(s, 6), [s[:3], s[3:].lstrip()])
+ self.assertEqual(convert_paragraph(s, 5), [s[:3], s[3:].lstrip()])
+ self.assertEqual(convert_paragraph(s, 4), [s[:2], s[2:].lstrip()])
+ else:
+ self.assertEqual(convert_paragraph(s, 10), [s])
+ self.assertEqual(convert_paragraph(s, 9), [s])
+ self.assertEqual(convert_paragraph(s, 8), [s[:4], s[4:].lstrip()])
+ self.assertEqual(convert_paragraph(s, 7), [s[:4], s[4:].lstrip()])
+ self.assertEqual(convert_paragraph(s, 6), [s[:3], s[3:].lstrip()])
+ self.assertEqual(convert_paragraph(s, 5), [s[:3], s[3:].lstrip()])
+ self.assertEqual(convert_paragraph(s, 4), [s[:2], s[2:].lstrip()])
+
+if __name__ == '__main__':
+ unittest.main()
--- a/usr/src/cmd/text-install/osol_install/text_install/text_install.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/text_install.py Wed Aug 11 15:34:19 2010 +0900
@@ -35,6 +35,8 @@
import subprocess
import sys
import traceback
+import locale
+import gettext
from optparse import OptionParser
import libbe
@@ -53,6 +55,7 @@
from osol_install.text_install.disk_selection import DiskScreen
from osol_install.text_install.fdisk_partitions import FDiskPart
from osol_install.text_install.help_screen import HelpScreen
+from osol_install.text_install.i18n import get_encoding
from osol_install.text_install.install_progress import InstallProgress
from osol_install.text_install.install_status import InstallStatus
from osol_install.text_install.log_viewer import LogViewer
@@ -97,6 +100,8 @@
logging.shutdown()
if logname is not None:
print _("Exiting Text Installer. Log is available at:\n%s") % logname
+ if isinstance(errcode, unicode):
+ errcode = errcode.encode(get_encoding())
sys.exit(errcode)
@@ -147,6 +152,8 @@
if __name__ == '__main__':
+ locale.setlocale(locale.LC_ALL, "")
+ gettext.install("textinstall", "/usr/share/locale", unicode=True)
if os.getuid() != 0:
print _("The OpenSolaris Text Installer must be run with "
"root privileges")
--- a/usr/src/cmd/text-install/osol_install/text_install/users.py Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/cmd/text-install/osol_install/text_install/users.py Wed Aug 11 15:34:19 2010 +0900
@@ -34,6 +34,7 @@
from osol_install.text_install.error_window import ErrorWindow
from osol_install.text_install.list_item import ListItem
from osol_install.text_install.window_area import WindowArea
+from osol_install.text_install.i18n import textwidth
class UserScreen(BaseScreen):
@@ -74,11 +75,11 @@
super(UserScreen, self).__init__(main_win)
self.max_text_len = (self.win_size_x - UserScreen.MAX_PASS_LEN -
UserScreen.ITEM_OFFSET) / 2
- max_field = max(len(UserScreen.ROOT_LABEL),
- len(UserScreen.CONFIRM_LABEL),
- len(UserScreen.NAME_LABEL),
- len(UserScreen.USERNAME_LABEL),
- len(UserScreen.USER_PASS_LABEL))
+ max_field = max(textwidth(UserScreen.ROOT_LABEL),
+ textwidth(UserScreen.CONFIRM_LABEL),
+ textwidth(UserScreen.NAME_LABEL),
+ textwidth(UserScreen.USERNAME_LABEL),
+ textwidth(UserScreen.USER_PASS_LABEL))
self.text_len = min(max_field + 1, self.max_text_len)
self.list_area = WindowArea(1, self.text_len, 0,
UserScreen.ITEM_OFFSET)
--- a/usr/src/pkg/manifests/system-install-text-install.mf Mon Aug 09 13:43:53 2010 -0700
+++ b/usr/src/pkg/manifests/system-install-text-install.mf Wed Aug 11 15:34:19 2010 +0900
@@ -95,6 +95,8 @@
file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/fdisk_partitions.pyc mode=0444
file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/help_screen.py mode=0444
file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/help_screen.pyc mode=0444
+file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/i18n.py mode=0444
+file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/i18n.pyc mode=0444
file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/inner_window.py mode=0444
file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/inner_window.pyc mode=0444
file path=usr/lib/python2.6/vendor-packages/osol_install/text_install/install_progress.py mode=0444