Support translation contexts

This commit is contained in:
James Westman 2021-11-24 21:12:26 -06:00
parent b0a8f3e2f5
commit 0e33ce190d
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
6 changed files with 55 additions and 31 deletions

View file

@ -91,7 +91,7 @@ Translations
~~~~~~~~~~~~ ~~~~~~~~~~~~
Use ``_("...")`` to mark strings as translatable. You can put a comment for Use ``_("...")`` to mark strings as translatable. You can put a comment for
translators on the line above. translators on the line above if needed.
.. code-block:: .. code-block::
@ -100,6 +100,18 @@ translators on the line above.
label: _("Hello, world!"); label: _("Hello, world!");
} }
Use ``C_("context", "...")`` to add a *message context* to a string to
disambiguate it, in case the same string appears in different places. Remember,
two strings might be the same in one language but different in another depending
on context.
.. code-block::
Gtk.Label label {
/* Translators: This is a section in the preferences window */
label: C_("preferences window", "Hello, world!");
}
Referencing objects by ID Referencing objects by ID
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -275,7 +275,6 @@ class Property(AstNode):
def emit_xml(self, xml: XmlEmitter): def emit_xml(self, xml: XmlEmitter):
values = self.children[Value] values = self.children[Value]
value = values[0] if len(values) == 1 else None value = values[0] if len(values) == 1 else None
translatable = isinstance(value, TranslatedStringValue)
bind_flags = [] bind_flags = []
if self.tokens["sync_create"]: if self.tokens["sync_create"]:
@ -286,12 +285,14 @@ class Property(AstNode):
props = { props = {
"name": self.tokens["name"], "name": self.tokens["name"],
"translatable": "true" if translatable else None,
"bind-source": self.tokens["bind_source"], "bind-source": self.tokens["bind_source"],
"bind-property": self.tokens["bind_property"], "bind-property": self.tokens["bind_property"],
"bind-flags": bind_flags_str, "bind-flags": bind_flags_str,
} }
if isinstance(value, TranslatedStringValue):
props = { **props, **value.attrs }
if len(self.children[Object]) == 1: if len(self.children[Object]) == 1:
xml.start_tag("property", **props) xml.start_tag("property", **props)
self.children[Object][0].emit_xml(xml) self.children[Object][0].emit_xml(xml)
@ -300,9 +301,6 @@ class Property(AstNode):
xml.put_self_closing("property", **props) xml.put_self_closing("property", **props)
else: else:
xml.start_tag("property", **props) xml.start_tag("property", **props)
if translatable:
xml.put_text(value.string)
else:
value.emit_xml(xml) value.emit_xml(xml)
xml.end_tag() xml.end_tag()
@ -357,11 +355,14 @@ class Value(ast.AstNode):
class TranslatedStringValue(Value): class TranslatedStringValue(Value):
@property @property
def string(self): def attrs(self):
return self.tokens["value"] attrs = { "translatable": "true" }
if "context" in self.tokens:
attrs["context"] = self.tokens["context"]
return attrs
def emit_xml(self, xml): def emit_xml(self, xml: XmlEmitter):
raise CompilerBugError("TranslatedStringValues must be handled by the parent AST node") xml.put_text(self.tokens["value"])
class LiteralValue(Value): class LiteralValue(Value):
@ -470,15 +471,12 @@ class BaseAttribute(AstNode):
def emit_xml(self, xml: XmlEmitter): def emit_xml(self, xml: XmlEmitter):
value = self.children[Value][0] value = self.children[Value][0]
translatable = isinstance(value, TranslatedStringValue) attrs = { self.attr_name: self.tokens["name"] }
attrs = {
self.attr_name: self.tokens["name"], if isinstance(value, TranslatedStringValue):
"translatable": "true" if translatable else None attrs = { **attrs, **value.attrs }
}
xml.start_tag(self.tag_name, **attrs) xml.start_tag(self.tag_name, **attrs)
if translatable:
xml.put_text(value.string)
else:
value.emit_xml(xml) value.emit_xml(xml)
xml.end_tag() xml.end_tag()

View file

@ -48,11 +48,8 @@ class Item(AstNode):
def emit_xml(self, xml: XmlEmitter): def emit_xml(self, xml: XmlEmitter):
value = self.children[Value][0] value = self.children[Value][0]
translatable = isinstance(value, TranslatedStringValue) attrs = value.attrs if isinstance(value, TranslatedStringValue) else {}
xml.start_tag("item", translatable="true" if translatable else None) xml.start_tag("item", **attrs)
if translatable:
xml.put_text(value.string)
else:
value.emit_xml(xml) value.emit_xml(xml)
xml.end_tag() xml.end_tag()

View file

@ -60,12 +60,23 @@ flags_value = Group(
translated_string = Group( translated_string = Group(
ast.TranslatedStringValue, ast.TranslatedStringValue,
AnyOf(
Sequence( Sequence(
Keyword("_"), Keyword("_"),
OpenParen(), OpenParen(),
UseQuoted("value").expected("a quoted string"), UseQuoted("value").expected("a quoted string"),
CloseParen().expected("`)`"), CloseParen().expected("`)`"),
), ),
Sequence(
Keyword("C_"),
OpenParen(),
UseQuoted("context").expected("a quoted string"),
Comma(),
UseQuoted("value").expected("a quoted string"),
Optional(Comma()),
CloseParen().expected("`)`"),
),
),
) )
value = AnyOf(translated_string, literal, flags_value, ident_value) value = AnyOf(translated_string, literal, flags_value, ident_value)

View file

@ -3,3 +3,6 @@ using Gtk 4.0;
Label { Label {
label: _("Hello, world!"); label: _("Hello, world!");
} }
Label {
label: C_("translation context", "Hello");
}

View file

@ -4,4 +4,7 @@
<object class="GtkLabel"> <object class="GtkLabel">
<property name="label" translatable="true">Hello, world!</property> <property name="label" translatable="true">Hello, world!</property>
</object> </object>
<object class="GtkLabel">
<property name="label" translatable="true" context="translation context">Hello</property>
</object>
</interface> </interface>