Merge: i18n annot: superstrings
authorJean Privat <jean@pryen.org>
Sat, 9 May 2015 01:23:37 +0000 (21:23 -0400)
committerJean Privat <jean@pryen.org>
Sat, 9 May 2015 01:23:37 +0000 (21:23 -0400)
Added the support of superstrings in the i18n annotation.

The first commit introduces a string format to use when replacing superstrings.
The second and third commits are updates to the i18n annotation and the test that goes along with it.

Pull-Request: #1319
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Jean Privat <jean@pryen.org>

examples/langannot.nit
examples/languages/en/LC_MESSAGES/langannot.po
examples/languages/fr/LC_MESSAGES/langannot.po
examples/languages/ja/LC_MESSAGES/langannot.po
examples/languages/langannot.pot
lib/standard/string.nit
src/frontend/i18n_phase.nit

index 7d471f6..cd294e1 100644 (file)
@@ -35,3 +35,9 @@ example
 
 of the language annotation capacities
 """
+
+var s = "example"
+
+print "This superstring {s} rocks"
+
+print "This superstring %1 rocks".format(s)
index e4e0d02..a3bd0f7 100644 (file)
@@ -6,4 +6,12 @@ msgstr "This String is a test"
 msgid "Multiline string\n\nexample\n\n\nof the language annotation capacities\n"
 msgstr "Multiline string\n\nexample\n\n\nof the language annotation capacities\n"
 
+#: langannot::langannot 39--9:17
+msgid "example"
+msgstr "example"
+
+#: langannot::langannot 41--7:34, langannot::langannot 43--7:33
+msgid "This superstring %1 rocks"
+msgstr "This superstring %1 rocks"
+
 # Generated file, do not modify
index 78ed2e7..0fbd368 100644 (file)
@@ -6,4 +6,12 @@ msgstr "Cette chaîne de caractères est un test"
 msgid "Multiline string\n\nexample\n\n\nof the language annotation capacities\n"
 msgstr "Example de\n\nchaine multiligne\n\n\navec annotation de localisation\n"
 
+#: langannot::langannot 39--9:17
+msgid "example"
+msgstr "exemple"
+
+#: langannot::langannot 41--7:34, langannot::langannot 43--7:33
+msgid "This superstring %1 rocks"
+msgstr "Cet %1 de superstring est génial"
+
 # Generated file, do not modify
index 1a50944..8cdb8e4 100644 (file)
@@ -6,4 +6,12 @@ msgstr "この文字列はてストです"
 msgid "Multiline string\n\nexample\n\n\nof the language annotation capacities\n"
 msgstr "複数行の文字列\n\nなサンプルプログラム\n\n\n新しい国際化アノテーションとともに\n"
 
+#: langannot::langannot 39--9:17
+msgid "example"
+msgstr "サンプル"
+
+#: langannot::langannot 41--7:34, langannot::langannot 43--7:33
+msgid "This superstring %1 rocks"
+msgstr "このスパ文字列%1は驚くべきです"
+
 # Generated file, do not modify
index f6c2096..9c86286 100644 (file)
@@ -6,4 +6,12 @@ msgstr ""
 msgid "Multiline string\n\nexample\n\n\nof the language annotation capacities\n"
 msgstr ""
 
+#: langannot::langannot 39--9:17
+msgid "example"
+msgstr ""
+
+#: langannot::langannot 41--7:34, langannot::langannot 43--7:33
+msgid "This superstring %1 rocks"
+msgstr ""
+
 # Generated file, do not modify
index cd2698c..5c9b2ef 100644 (file)
@@ -849,6 +849,39 @@ abstract class Text
                return hash_cache.as(not null)
        end
 
+       # Gives the formatted string back as a Nit string with `args` in place
+       #
+       #       assert "This %1 is a %2.".format("String", "formatted String") == "This String is a formatted String"
+       #       assert "\\%1 This string".format("String") == "\\%1 This string"
+       fun format(args: Object...): String do
+               var s = new Array[Text]
+               var curr_st = 0
+               var i = 0
+               while i < length do
+                       # Skip escaped characters
+                       if self[i] == '\\' then
+                               i += 1
+                       # In case of format
+                       else if self[i] == '%' then
+                               var fmt_st = i
+                               i += 1
+                               var ciph_st = i
+                               while i < length and self[i].is_numeric do
+                                       i += 1
+                               end
+                               i -= 1
+                               var fmt_end = i
+                               var ciph_len = fmt_end - ciph_st + 1
+                               s.push substring(curr_st, fmt_st - curr_st)
+                               s.push args[substring(ciph_st, ciph_len).to_i - 1].to_s
+                               curr_st = i + 1
+                       end
+                       i += 1
+               end
+               s.push substring(curr_st, length - curr_st)
+               return s.to_s
+       end
+
 end
 
 # All kinds of array-based text representations.
index f068dc1..60bcdf9 100644 (file)
@@ -108,6 +108,19 @@ private class StringFinder
                if e isa AAnnotation then return
                super
        end
+
+       # Adds a String to the list of strings of the module
+       #
+       # The string needs to be pre-formatted to C standards (escape_to_c)
+       fun add_string(s: String, loc: Location) do
+               var locstr = "{amodule.mmodule.mgroup.name}::{amodule.mmodule.name} {loc.line_start}--{loc.column_start}:{loc.column_end}"
+               if not strings.has_key(s) then
+                       var po = new PObject([locstr], s, "")
+                       strings[s] = po
+               else
+                       strings[s].locations.push locstr
+               end
+       end
 end
 
 redef class ANode
@@ -119,15 +132,35 @@ redef class AStringExpr
        redef fun accept_string_finder(v) do
                var str = value.as(not null).escape_to_c
                var parse = v.toolcontext.parse_expr("\"{str}\".get_translation(\"{v.domain}\", \"{v.languages_location}\").unescape_nit")
-               var loc = location
-               var locstr = "{v.amodule.mmodule.mgroup.name}::{v.amodule.mmodule.name} {loc.line_start}--{loc.column_start}:{loc.column_end}"
-               if not v.strings.has_key(str) then
-                       var po = new PObject([locstr], str, "")
-                       v.strings[str] = po
-               else
-                       v.strings[str].locations.push locstr
-               end
                replace_with(parse)
+               v.add_string(str, location)
+       end
+end
+
+redef class ASuperstringExpr
+
+       redef fun accept_string_finder(v) do
+               var fmt = ""
+               var exprs = new Array[AExpr]
+               for i in n_exprs do
+                       if i isa AStringFormExpr then
+                               fmt += i.value.as(not null)
+                       else
+                               fmt += "%"
+                               exprs.push i
+                               fmt += exprs.length.to_s
+                       end
+               end
+               fmt = fmt.escape_to_c
+               v.add_string(fmt, location)
+               var parse = v.toolcontext.parse_expr("\"{fmt}\".get_translation(\"{v.domain}\", \"{v.languages_location}\").unescape_nit.format()")
+               if not parse isa ACallExpr then
+                       v.toolcontext.error(location, "Fatal error in i18n annotation, the parsed superstring could not be generated properly")
+                       return
+               end
+               var parse_exprs = parse.n_args.n_exprs
+               parse_exprs.add_all exprs
+               replace_with parse
        end
 end