[Sciviews-commits] r240 - in pkg/svIDE: . R man

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Tue Dec 29 12:14:31 CET 2009


Author: phgrosjean
Date: 2009-12-29 12:14:28 +0100 (Tue, 29 Dec 2009)
New Revision: 240

Added:
   pkg/svIDE/R/kpfTranslate.R
   pkg/svIDE/man/kpfTranslate.Rd
Modified:
   pkg/svIDE/DESCRIPTION
   pkg/svIDE/NAMESPACE
   pkg/svIDE/NEWS
Log:
Komodo projects/packages translation function using poEdit added in svIDE

Modified: pkg/svIDE/DESCRIPTION
===================================================================
--- pkg/svIDE/DESCRIPTION	2009-12-28 15:25:20 UTC (rev 239)
+++ pkg/svIDE/DESCRIPTION	2009-12-29 11:14:28 UTC (rev 240)
@@ -2,10 +2,10 @@
 Type: Package
 Title: SciViews GUI API - IDE and code editor functions
 Depends: R (>= 2.6.0)
-Imports: utils, tcltk, svMisc
+Imports: utils, tcltk, svMisc, XML
 Description: Function for the GUI API to interact with external IDE/code editors
-Version: 0.9-47
-Date: 2009-10-26
+Version: 0.9-48
+Date: 2009-12-29
 Author: Philippe Grosjean
 Maintainer: Philippe Grosjean <phgrosjean at sciviews.org>
 License: GPL (>= 2)

Modified: pkg/svIDE/NAMESPACE
===================================================================
--- pkg/svIDE/NAMESPACE	2009-12-28 15:25:20 UTC (rev 239)
+++ pkg/svIDE/NAMESPACE	2009-12-29 11:14:28 UTC (rev 240)
@@ -1,4 +1,4 @@
-import(utils, tcltk, svMisc)
+import(utils, tcltk, svMisc, XML)
 
 export(createCallTipFile,
        createSyntaxFile,
@@ -7,4 +7,8 @@
        guiCallTip,
 	   guiComplete,
        guiDDEInstall,
-	   Source)
+	   Source,
+	   kpf2pot,
+	   kpz2pot,
+	   kpfTranslate,
+	   kpzTranslate)

Modified: pkg/svIDE/NEWS
===================================================================
--- pkg/svIDE/NEWS	2009-12-28 15:25:20 UTC (rev 239)
+++ pkg/svIDE/NEWS	2009-12-29 11:14:28 UTC (rev 240)
@@ -1,5 +1,12 @@
 = svIDE News
 
+== Changes in svIDE 0.9-48
+
+* Addition of kpf2pot(), kpz2pot(), kpfTranslate() and kpzTranslate() to allow
+  translation of Komodo project or package using poEdit. Introduces a new
+  dependency on XML R package on CRAN.
+
+
 == Changes in svIDE 0.9-47
 
 * guiComplete now does not have a givetype argument any more. Extra information

Added: pkg/svIDE/R/kpfTranslate.R
===================================================================
--- pkg/svIDE/R/kpfTranslate.R	                        (rev 0)
+++ pkg/svIDE/R/kpfTranslate.R	2009-12-29 11:14:28 UTC (rev 240)
@@ -0,0 +1,270 @@
+# Make a .pot file with translatable strings found in a Komodo project/package
+# Translatable strings are:
+# 1) All names
+# 2) In snippets:
+#    [[%ask:R-desc:XXX]]
+#    [[%ask:R-tip:XXX]]
+#    [[%ask|pref:URL-help:XXX]] and [[%ask|pref:RWiki-help:XXX]]
+#    [[%tr:XXX]
+# 3) In macros:
+#    Strings inside _("XXX"), with _() being a function returning its argument
+kpf2pot <- function (kpfFile, potFile) {
+    if (missing(potFile)) 
+        potFile <- sub("\\.kpf", ".pot", kpfFile)
+	if (kpfFile == potFile)
+		potFile <- paste(kpfFile, "pot", sep = ".")
+	# Extract translatable strings from this file
+	doc <- xmlRoot(xmlTreeParse(kpfFile))
+	imax <- xmlSize(doc)
+	if (imax < 1) stop("No node found in the file!")
+	# Collect all strings to be translated
+	s <- character(0)
+	for (i in 1:imax) {
+		n <- xmlGetAttr(doc[[i]], "name")
+		if (!is.null(n)) {
+			s <- c(s, n) 
+			type <- xmlName(doc[[i]])
+			# If this is a snippet, look for other translatable strings
+			if (type == "snippet") {
+				snip <- xmlValue(doc[[i]])
+				chunks <- strsplit(snip, "\\[\\[|\\]\\]")[[1]]
+				# Keep only chunks starting with R-desc:, R-tip:, URL-help:
+				# RWiki-help: or %tr:
+				chunks <- chunks[grep("^%ask:R-desc:|^%ask:R-tip:|^%ask:URL-help:|^%ask:RWiki-help:|^%pref:URL-help|^%pref:RWiki-help|%tr:", chunks)]
+				# Are there any remaining chunks?
+				l <- length(chunks)
+				if (l > 0) {
+					# Eliminate leading stuff
+					chunks <- sub("^%ask:[^:]+:|%tr:", "", chunks)
+					# and add to the list of items to translate
+					s <- c(s, chunks)
+				}
+			} else if (type == "macro") {
+				mac <- xmlValue(doc[[i]])
+				# Collect tagged strings (i.e., strings inside _(...))
+				repeat {
+					str <- sub("^.*_\\(\"(.*[^\\\\])\"\\).*$", "\\1", mac)
+					if (str == mac) break
+					s <- c(s, gsub('\\\\"', '"', str))
+					mac <- sub("^(.*)(_\\(\".*[^\\\\]\"\\))(.*)$",
+						"\\1(...)\\3", mac)
+				}
+				repeat {
+					str <- sub("^.*_\\('(.*[^\\\\])'\\).*$", "\\1", mac)
+					if (str == mac) break
+					s <- c(s, gsub("\\\\'", "'", str))
+					mac <- sub("^(.*)(_\\('.*[^\\\\]'\\))(.*)$",
+						"\\1(...)\\3", mac)
+				}
+			}
+		}
+	}
+	# Keep only unique strings
+	s <- unique(s)
+	s <- s[nzchar(s)]
+    tmp <- shQuote(encodeString(s), type = "cmd")
+    con <- file(potFile, "wt")
+    on.exit(close(con))
+    writeLines(con = con, c("msgid \"\"", "msgstr \"\"",
+		sprintf("\"Project-Id-Version: R %s.%s\\n\"", 
+        R.version$major, R.version$minor),
+		"\"Report-Msgid-Bugs-To: support at sciviews.org\\n\"", 
+        paste("\"POT-Creation-Date: ", format(Sys.time(), "%Y-%m-%d %H:%M"), 
+            "\\n\"", sep = ""),
+		"\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"", 
+        "\"Last-Translator: FULL NAME <EMAIL at ADDRESS>\\n\"", 
+        "\"Language-Team: LANGUAGE <LL at li.org>\\n\"",
+		"\"MIME-Version: 1.0\\n\"", 
+        "\"Content-Type: text/plain; charset=utf-8\\n\"",
+		"\"Content-Transfer-Encoding: 8bit\\n\"", 
+        ""))
+    for (e in tmp)
+		writeLines(con = con, c("", paste("msgid", e), "msgstr \"\""))
+	# Check that the .pot file is created
+	return(invisible(file.exists(potFile)))	
+}
+
+kpz2pot <- function (kpzFile, potFile) {
+    if (missing(potFile)) 
+        potFile <- sub("\\.kpz", ".pot", kpzFile)
+	if (kpzFile == potFile)
+		potFile <- paste(kpzFile, "pot", sep = ".")
+    # The kpz file is a zipped file containing package.kpf in a subdirectory
+	f <- file.path(tempdir(), "package.kpf")
+	unlink(f)	# Make sure the file does not exist yet
+	unzip(kpzFile, junkpaths = TRUE, exdir = tempdir())
+	if (!file.exists(file.path(tempdir(), "package.kpf")))
+		stop("Impossible to extract the content of the .kpz file.")
+	# Run kpf2pot() on this file
+	kpf2pot(f, potFile)	
+	# Delete extracted file
+	unlink(f)
+	# Check that the .pot file is created
+	return(invisible(file.exists(potFile)))
+}
+
+kpfTranslate <- function (kpfFile, lang, poFile, kpf2File) {
+    if (missing(lang))
+		stop("You must provide 'lang' (ex.: 'fr', or 'de')")
+	po <- paste("-", lang, ".po", sep = "")
+	kpf2 <- paste("-", lang, ".kpf", sep = "")
+	if (missing(poFile)) 
+        poFile <- sub("\\.kpf", po, kpfFile)
+	if (kpfFile == poFile)
+		poFile <- paste(kpfFile, po, sep = "")
+	if (!file.exists(poFile))
+		stop("'poFile' not found!")
+	if (missing(kpf2File)) {
+		kpf2File <- sub("\\.kpf", kpf2, kpfFile)
+		if (kpfFile == kpf2File)
+			kpf2File <- paste(kpfFile, kpf2, sep = "")
+		unlink(kpf2File)  # Make sure we create a new resulting file
+	}
+	
+	# Read the content of the .po file
+	tr <- readLines(poFile, encoding = "UTF-8")
+	# Keep only lines starting with msgid or msgstr
+	trid <- tr[regexpr("^msgid ", tr) == 1]
+	trid <- sub("^msgid ", "", trid)
+	trmsg <- tr[regexpr("^msgstr ", tr) == 1]
+	trmsg <- sub("^msgstr ", "", trmsg)
+	# Check that both trid and trmsg have same length
+	if (length(trid) != length(trmsg))
+		stop("Unequal number of id and translated strings in the .po file!")
+	keep <- trid != "\"\""
+	trid <- trid[keep]
+	trmsg <- trmsg[keep]
+
+	# We need to "unquote" the strings
+	unquote <- function (s) {
+		# Replace any \\\" by \"
+		s <- gsub("\\\\\"", "\"", s)
+		# Eliminate leading and trailing quotes
+		s <- sub("^\"", "", s)
+		s <- sub("\"$", "", s)
+		return(s)
+	}
+	trid <- unquote(trid)
+	trmsg <- unquote(trmsg)
+	names(trmsg) <- trid
+	
+	# Extract translatable strings from the .kpf file
+	doc <- xmlRoot(xmlTreeParse(kpfFile))
+	imax <- xmlSize(doc)
+	if (imax < 1) stop("No node found in the file!")
+	# Collect all strings to be translated
+	trans <- function (s) {
+		tr <- as.character(trmsg[s])
+		if (is.na(tr) || tr == "") return(s) else return(tr)
+	}
+	
+	s <- character(0)
+	for (i in 1:imax) {
+		n <- xmlGetAttr(doc[[i]], "name")
+		if (!is.null(n)) {
+			# Replace name in attributes of this node
+			node <- addAttributes(doc[[i]], name = trans(n), append = TRUE)
+			type <- xmlName(node)
+			# If this is a snippet, look for other translatable strings
+			if (type == "snippet") {
+				snip <- xmlValue(node)
+				chunks <- strsplit(snip, "\\[\\[|\\]\\]")[[1]]
+				# Translate chunks starting with R-desc:, R-tip:, URL-help:,
+				# RWiki-help: or %tr:
+				toTrans <- grep("^%ask:R-desc:|^%ask:R-tip:|^%ask:URL-help:|^%ask:RWiki-help:|^%pref:URL-help|^%pref:RWiki-help|%tr:", chunks)
+				if (length(toTrans) > 0) {
+					for (j in toTrans) {
+						msg <- sub("^%ask:[^:]+:|%tr:", "", chunks[j])
+						header <- sub("^(%ask:[^:]+:|%tr:).*$", "\\1", chunks[j])
+						chunks[j] <- paste(header, trans(msg), sep = "")
+					}
+					# Reconstitute the snippet content using translated messages
+					snip <- paste(chunks, c("[[", "]]"),
+						sep = "", collapse = "")
+					# We need to eliminate latest '[['
+					snip <- sub("\\[\\[$", "", snip)
+					xmlValue(node) <- snip
+				}
+			} else if (type == "macro") {
+				mac <- xmlValue(node)
+				# Translate tagged strings (i.e., strings inside _(...))
+				repeat {
+					str <- sub("^.*_\\(\"(.*[^\\\\])\"\\).*$", "\\1", mac)
+					if (str == mac) break
+					s <- trans(gsub('\\\\"', '"', str))
+					s <- gsub('"', '\\"', s)
+					mac <- sub("^(.*)(_\\(\".*[^\\\\]\"\\))(.*)$",
+						paste("\\1%%%%%%(\"", s, "\")\\3", sep = ""), mac)
+				}
+				repeat {
+					str <- sub("^.*_\\('(.*[^\\\\])'\\).*$", "\\1", mac)
+					if (str == mac) break
+					s <- trans(gsub("\\\\'", "'", str))
+					s <- gsub("'", "\\'", s)
+					mac <- sub("^(.*)(_\\('.*[^\\\\]'\\))(.*)$",
+						paste("\\1%%%%%%('", s, "')\\3", sep = ""), mac)
+				}
+				mac <- gsub("%%%%%%", "_", mac)
+				xmlValue(node) <- mac
+			}
+			# Replace the node with its translated version
+			doc[[i]] <- node
+		}
+	}
+	# In case the project has a name, we change it now
+	projname <- xmlGetAttr(doc, "name")
+	if (!is.null(projname))
+		doc <- addAttributes(doc, name = basename(kpf2File), append = TRUE)
+	
+	# Save the translated XML content into the second .kpf file
+	saveXML(doc, file = kpf2File, prefix = '<?xml version="1.0" encoding="UTF-8"?>\n<!-- Komodo Project File - DO NOT EDIT -->\n')
+	# Check that the new .kpf file is produced
+	return(invisible(file.exists(kpf2File)))	
+}
+
+kpzTranslate <- function (kpzFile, lang, poFile, kpz2File) {
+    if (missing(lang))
+		stop("You must provide 'lang' (ex.: 'fr', or 'de')")
+	po <- paste("-", lang, ".po", sep = "")
+	kpz2 <- paste("-", lang, ".kpz", sep = "")
+	if (missing(poFile)) 
+        poFile <- sub("\\.kpz", po, kpzFile)
+	if (kpzFile == poFile)
+		poFile <- paste(kpzFile, po, sep = "")
+	if (!file.exists(poFile))
+		stop("'poFile' not found!")
+	if (missing(kpz2File))
+		kpz2File <- sub("\\.kpz", kpz2, kpzFile)
+	if (kpzFile == kpz2File)
+		kpz2File <- paste(kpzFile, kpz2, sep = "")
+	unlink(kpz2File)  # Make sure we create a new resulting file
+	
+    # The kpz file is a zipped file containing package.kpf in a subdirectory
+	f <- file.path(tempdir(), "package.kpf")
+	unlink(f)	# Make sure the file does not exist yet
+	unzip(kpzFile, junkpaths = TRUE, exdir = tempdir())
+	if (!file.exists(file.path(tempdir(), "package.kpf")))
+		stop("Impossible to extract the content of the .kpz file.")
+	
+	# Call kpfTranslate on the created package.kpf file
+	kpfTranslate(f, lang, poFile, f)
+	
+	# Compress the file in a kpz zipped archive named kpz2File
+	# Create a directory of the same name as the package
+	d <- sub("\\\\.kpz$", "", basename(kpz2File))
+	d <- file.path(dirname(f), d)
+	dir.create(d)
+	# Move the package.kpf file there
+	f2 <- file.path(d, "package.kpf")
+	file.copy(f, f2)
+	unlink(f)
+	# Compress (zip) the directory
+	odir <- getwd()
+	on.exit(setwd(odir))
+	setwd(dirname(kpz2File))
+	# Note: the 'zip' program must be accessible!
+	cmd <- paste('zip -rqm9 "', basename(kpz2File), '" "', d, '"', sep = "")
+	try(system(cmd, intern = TRUE, wait = TRUE), silent = TRUE)
+	# Check that the file is produced
+	return(invisible(file.exists(kpz2File)))
+}

Added: pkg/svIDE/man/kpfTranslate.Rd
===================================================================
--- pkg/svIDE/man/kpfTranslate.Rd	                        (rev 0)
+++ pkg/svIDE/man/kpfTranslate.Rd	2009-12-29 11:14:28 UTC (rev 240)
@@ -0,0 +1,112 @@
+\name{kpfTranslate}
+\alias{kpf2pot}
+\alias{kpz2pot}
+\alias{kpfTranslate}
+\alias{kpzTranslate}
+
+\title{ Create a POT file or use a PO file to allow translating Komodo project (.kpf) or package (.kpz) }
+
+\description{
+  Komodo Edit/IDE snippets are static elements and do not allow to use translation
+  facilites easily. The \code{kpX2pot()} and \code{kpXTranslate()} functions
+  provide a mechanism to use poEdit, a program designed to translate strings for
+  software to ease and automatise translation of Komodo projets or packages (see details section).
+}
+
+\usage{
+kpf2pot(kpfFile, potFile)
+kpz2pot(kpzFile, potFile)
+kpfTranslate(kpfFile, lang, poFile, kpf2File)
+kpzTranslate(kpzFile, lang, poFile, kpz2File)
+}
+
+\arguments{
+  \item{kpfFile}{ A Komodo project file with a .kpf extension to be translated }
+  \item{kpzFile}{ A Komodo package file with a .kpz extension to be translated  }
+  \item{potFile}{ The name of a .pot file providing strings to be translated,
+    if not provided, it is the same name as the .kpf/.kpz file, but with a .pot
+    extension instead }
+  \item{lang}{ The language to translate to, for instance, 'fr' for French,
+    'de' for German, 'it' for Italian, 'en_GB' for Great Britain's English, etc. }
+  \item{poFile}{ The path to the .po file containing the translations. If not
+    provided, it is assumed to be the basename of the .kpf/.kpz file without
+    extension, plus '-' and lang and with a .po extension in the same directory
+    as the .kpf/.kpz file. For instance, the default translation file for
+    \code{myproject.kpf} into French is named \code{myproject-fr.po}. }
+  \item{kpf2File}{ The Komodo project file to create with the translation. If
+    not provided, it is assumed to be the same as the initial project file, but
+    with '-' and lang appended to the base name. For instance, the French
+    translation of \code{myproject.kpf} would be \code{myproject-fr.kpf} in the
+    same directory, by default. }
+  \item{kpz2File}{ Same as kpf2File, but for Komodo package files with a .kpz
+    extension. }
+}
+\value{
+  These functions return invisibly \code{TRUE} if the targetted file is create,
+  or \code{FALSE} otherwise.
+}
+
+\details{ 
+  Komodo Edit/IDE are code editor programs that can be used to edit R code
+  efficiently with the SciViews-K plugin (see http://www.sciviews.org/SciViews-K).
+  Komodo can be customized by using projects files (by project customization) with
+  a .kpf extension, or tools collected together in the toolbox and that can be
+  saved on disk in Komodo package files with a .kpz extension.
+  
+  Among the tools you can place in a Komodo project or package, there are macros
+  (written in JavaScript or Python). Thanks to the SciViews-K plugin, you have
+  access to R and R code inside these macros. This makes it a good candidated for
+  writing GUI elements, including dialog boxes, on top of your favorite R code
+  editor. You can also add 'snippets' in those projects/packages. Snippets are
+  short pieces of code, including R code, you can save and retrieve easily. In the
+  snippets, you can define replaceable parts, includings parts you replace after
+  prompting the user with a dialog box. SciViews uses these features extensively,
+  for instance, for the 'R reference' toolbox.
+  
+  Unfortunately, theses tools do not benefit easily from translation features. So,
+  it is hard to maintain the same project/package in different languages. The
+  functions provided here ease the maintenance of such projects/packages translated
+  in various languages. Here is how you can use them:
+  
+  1) Save your Komodo project or package on disk.
+  
+  2) Use the \code{kpX2pot()} function to create, or update the .pot file. This
+  file lists all translatable strings found in the project/package. Translatable
+  strings are: (a) names of tools or folders, (b) items in snippets that are
+  flagged with \%ask:R-desc:, \%ask:R-tip:, \%ask:URL-help:, \%ask:RWiki-help:,
+  \%pref:URL-help:, \%pref:RWiki-help, and \%tr: (see Komodo help to learn how to
+  use these tags in snippets), and (c) strings in JavaScript macros that are
+  flagged with \code{_()}. For instance, creating a .pot file for
+  \code{~/myproject.kpf} is as simple as calling \code{kpf2pot("~/myproject.kpf")}.
+  
+  3) Use the poEdit program (search Google to find, download and install this
+  free Open Source translation utility, if you don't have it yet) to translate
+  the extracted strings. The first time, you create a .po file based on the .pot
+  template you just created. For subsequent versions of your project/package, you
+  reuse the old .po file and select menu entry 'Catalog -> Update from POT file...'
+  to update your translation file with new strings found in the .pot file. You
+  are better to place the .po file in the same directory as your project/package
+  and to give it the same name, but replacing .kpX by -<lang>.po, where <lang>
+  is the language in which you do the translation. You can distribute .pot files
+  to a staff of translators that would send you back the created/modified .po
+  files for compilation. See the poEdit documentation for further help (note that
+  multiline strings and singular/plural forms are not supported yet).
+  
+  4) Once you have your .po file ready, you can translate your Komodo project/package
+  in that language easily from R. For instance, a project file \code{~/myproject.kpf}
+  can be translated in French, using the .po file \code{~/myproject-fr.po} that
+  contains French translation of your strings by issuing in R
+  \code{kpfTranslate("~/myproject.kpf", "fr")}. That produces a \code{~/myproject-fr.kpf}
+  file that contains your Komodo project translated in French. Please, note that
+  \code{kpzTranslate()} currently needs to access the external \code{zip} program
+  for zipping the .kpz file. This program is usually accessible from within Linux
+  or Mac OS X by default, but needs to be installed (and made accessible through
+  the PATH) under Windows.
+  
+  5) To open your translated project/package in Komodo, just drag and drop the new
+  file on the central area of the Komodo window.
+}
+
+\author{ Philippe Grosjean <phgrosjean at sciviews.org> }
+
+\keyword{ utilities }



More information about the Sciviews-commits mailing list