<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>http://wiki.mipt.ru/index.php?action=history&amp;feed=atom&amp;title=Development%3ALanguages%3ATim%27s_crazy_proposal_based_on_maketext</id>
	<title>Development:Languages:Tim&#039;s crazy proposal based on maketext - История изменений</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.mipt.ru/index.php?action=history&amp;feed=atom&amp;title=Development%3ALanguages%3ATim%27s_crazy_proposal_based_on_maketext"/>
	<link rel="alternate" type="text/html" href="http://wiki.mipt.ru/index.php?title=Development:Languages:Tim%27s_crazy_proposal_based_on_maketext&amp;action=history"/>
	<updated>2026-05-07T06:59:12Z</updated>
	<subtitle>История изменений этой страницы в вики</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>http://wiki.mipt.ru/index.php?title=Development:Languages:Tim%27s_crazy_proposal_based_on_maketext&amp;diff=11290&amp;oldid=prev</id>
		<title>Олег Давидович: 1 версия импортирована</title>
		<link rel="alternate" type="text/html" href="http://wiki.mipt.ru/index.php?title=Development:Languages:Tim%27s_crazy_proposal_based_on_maketext&amp;diff=11290&amp;oldid=prev"/>
		<updated>2024-10-21T08:51:23Z</updated>

		<summary type="html">&lt;p&gt;1 версия импортирована&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;ru&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Предыдущая версия&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Версия от 08:51, 21 октября 2024&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;ru&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(нет различий)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Олег Давидович</name></author>
	</entry>
	<entry>
		<id>http://wiki.mipt.ru/index.php?title=Development:Languages:Tim%27s_crazy_proposal_based_on_maketext&amp;diff=11289&amp;oldid=prev</id>
		<title>1&gt;Mina: /* Proposed runtime lang file syntax */ Typo</title>
		<link rel="alternate" type="text/html" href="http://wiki.mipt.ru/index.php?title=Development:Languages:Tim%27s_crazy_proposal_based_on_maketext&amp;diff=11289&amp;oldid=prev"/>
		<updated>2009-11-23T12:07:50Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;Proposed runtime lang file syntax: &lt;/span&gt; Typo&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;They say that the border between madness and genius is is very narrow. Here goes.&lt;br /&gt;
&lt;br /&gt;
The best article I know about the problems of localising software is http://search.cpan.org/~ferreira/Locale-Maketext-1.13_82/lib/Locale/Maketext/TPJ13.pod. I particularly like the narrative in the first half. Also, I must warn you that I have not read much about localisation, so my endorsement may not mean much.&lt;br /&gt;
&lt;br /&gt;
OK, so the key point it makes is that really, a language string like &amp;quot;There have been $a quiz attempts&amp;quot; is really a function (in the mathematical sense of a mapping, not necessarily as a programming language construct). Depending on $a, we want it to output&lt;br /&gt;
* There have been no quiz attempts&lt;br /&gt;
* There has been one quiz attempt&lt;br /&gt;
* There have been 42 quiz attempts&lt;br /&gt;
&lt;br /&gt;
So the question is, why not make it a function in the programming language construct sense as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Two representations==&lt;br /&gt;
&lt;br /&gt;
Up to Moodle 1.9, the files Moodle used at runtime were exactly the same as the files that translators edited. That was convenient, but limited us to a human-readable and editable format. Also, it meant that Moodle had to do a lot of searching at runtime.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 we are already proposing to split the representations, which lets us optimise the runtime format to be pretty much whatever we like, without making the format edited by translators impossible.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Proposed runtime lang file syntax==&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;moodledata/lang/&amp;lt;/tt&amp;gt; there are subfolders like &amp;lt;tt&amp;gt;en/&amp;lt;/tt&amp;gt; (note we lose the legacy &amp;lt;tt&amp;gt;_utf8&amp;lt;/tt&amp;gt;) that contains files like &amp;lt;tt&amp;gt;mod_quiz.php&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;core_moodle.php&amp;lt;/tt&amp;gt;, that is, using the new component naming convention.&lt;br /&gt;
&lt;br /&gt;
Suppose we have a hypothetical plugin &amp;lt;tt&amp;gt;admin/report/dylan&amp;lt;/tt&amp;gt; with its current lang file &amp;lt;tt&amp;gt;admin/report/dylan/lang/en_utf8/report_dylan.php&amp;lt;/tt&amp;gt; that contains:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$string[&amp;#039;howmanyroads&amp;#039;] = &amp;#039;How many roads must a man walk down?&amp;#039;;&lt;br /&gt;
$string[&amp;#039;roadsx&amp;#039;] = &amp;#039;Roads: $a&amp;#039;;&lt;br /&gt;
$string[&amp;#039;xroadsfromytowns&amp;#039;] = &amp;#039;$a-&amp;gt;numroads roads from at least $a-&amp;gt;numcities different cities.&amp;#039;;&lt;br /&gt;
// Can&amp;#039;t really handle pluralisation in that last one in Moodle :-(&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In my new proposal, &amp;lt;tt&amp;gt;moodledata/lang/en/report_dylan.php&amp;lt;/tt&amp;gt; will contain:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
class strings_en_report_capability extends strings_base {&lt;br /&gt;
    protected static $helper = lang_helper_en::get(); // Get singleton instance.&lt;br /&gt;
    public function howmanyroads($a) { return &amp;#039;How many roads must a man walk down?&amp;#039;; }&lt;br /&gt;
    public function roadsx($a) { return self::$helper-&amp;gt;quant($a, &amp;#039;road&amp;#039;); }&lt;br /&gt;
    public function xroadsfromytowns($a) { &lt;br /&gt;
        return self::$helper-&amp;gt;quant($a-&amp;gt;numroads, &amp;#039;road&amp;#039;) . &amp;#039; from at least &amp;#039; .&lt;br /&gt;
                self::$helper-&amp;gt;quant($a-&amp;gt; numcities, &amp;#039;different city&amp;#039;, &amp;#039;different cities&amp;#039;) . &amp;#039;.&amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
(I manually line-wrapped that last example to make it readable. in reality, remember that this file is being automatically compiled from some more human-readiable source.)&lt;br /&gt;
&lt;br /&gt;
Also note that &amp;lt;tt&amp;gt;moodledata/lang/fr/report_dylan.php&amp;lt;/tt&amp;gt; will look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
include_once($CFG-&amp;gt;langdir . &amp;#039;/en/report_dylan.php&amp;#039;);&lt;br /&gt;
class strings_fr_report_capability extends strings_en_report_capability {&lt;br /&gt;
    protected static $helper = lang_helper_fr::get(); // Get singleton instance.&lt;br /&gt;
    public function howmanyroads() { return &amp;#039;Combien de rue ...&amp;#039;; }&lt;br /&gt;
    // etc.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And &amp;lt;tt&amp;gt;moodledata/lang/fr_ca/report_dylan.php&amp;lt;/tt&amp;gt; is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
include_once($CFG-&amp;gt;langdir . &amp;#039;/fr/report_dylan.php&amp;#039;);&lt;br /&gt;
class strings_fr_ca_report_capability extends strings_en_report_capability {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Using that runtime format==&lt;br /&gt;
&lt;br /&gt;
Then, &amp;lt;tt&amp;gt;string_manager()&amp;lt;/tt&amp;gt; becomes:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class string_manager {&lt;br /&gt;
    protected $stringclasses = array();&lt;br /&gt;
    public function get_string($identifier, $component = &amp;#039;&amp;#039;, $a = null) {&lt;br /&gt;
        $component = $this-&amp;gt;fix_legacy_component_names($component);&lt;br /&gt;
        $this-&amp;gt;get_string_class(current_language(), $component)-&amp;gt;$identifier($a);&lt;br /&gt;
    }&lt;br /&gt;
    protected function get_string_class($lang, $component) {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
        if (!isset($this-&amp;gt;stringclasses[$lang][$component])) {&lt;br /&gt;
            $this-&amp;gt;stringclasses[$lang][$component] = &lt;br /&gt;
                    $this-&amp;gt;load_string_class($lang, $component)();&lt;br /&gt;
        }&lt;br /&gt;
        return $this-&amp;gt;stringclasses[$lang][$component];&lt;br /&gt;
    }&lt;br /&gt;
    protected function load_string_class($lang, $component) {&lt;br /&gt;
        $file = &amp;quot;$CFG-&amp;gt;langdir/$lang/$component.php&amp;quot;;&lt;br /&gt;
        $class = &amp;quot;strings_{$lang}_{$component}&amp;quot;;&lt;br /&gt;
        if ($CFG-&amp;gt;langediting &amp;amp;&amp;amp; !$this-&amp;gt;is_up_to_date($file)) {&lt;br /&gt;
            compile_lang_strings($lang, $component);&lt;br /&gt;
        }&lt;br /&gt;
        if (!is_readable($file)) {&lt;br /&gt;
            return new strings_base(); // See below.&lt;br /&gt;
        }&lt;br /&gt;
        include_once($file);&lt;br /&gt;
        if (!class_exists()) {&lt;br /&gt;
            throw new coding_exception($file . &amp;#039; did not define the &amp;#039; . $class .&lt;br /&gt;
                    &amp;#039;class. There must be a bug in compile_lang_strings.&amp;#039;);&lt;br /&gt;
        }&lt;br /&gt;
        return new $class();&lt;br /&gt;
    }&lt;br /&gt;
    // A few other methods omitted.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note that if you have a developer/translator flag on (&amp;lt;tt&amp;gt;$CFG-&amp;gt;langediting&amp;lt;/tt&amp;gt;) then &amp;lt;tt&amp;gt; is_up_to_date&amp;lt;/tt&amp;gt; checks various file timestamps, so that lang files can automatically be recompiled as needed for those people, without hurting runtime performance for production sites. &lt;br /&gt;
&lt;br /&gt;
As a final bit of magic, we have&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class strings_base {&lt;br /&gt;
    public function __call($name, $arguments) {&lt;br /&gt;
        return &amp;quot;[[$name]]&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Remember that the strings_en_report_capability inherited form this. This gives us our classing missing string fallback. Also:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class lang_helper_en {&lt;br /&gt;
    private static $inst = null;&lt;br /&gt;
    public static get() {&lt;br /&gt;
        if (!$inst) {&lt;br /&gt;
            $inst = new lang_helper_en();&lt;br /&gt;
        }&lt;br /&gt;
        return $inst;&lt;br /&gt;
    }&lt;br /&gt;
    public function quant($number, $singular, $plural = &amp;#039;&amp;#039;) {&lt;br /&gt;
        if ($number = 1) {&lt;br /&gt;
            return &amp;quot;$number $singular&amp;quot;;&lt;br /&gt;
        } else if ($plural) {&lt;br /&gt;
            return &amp;quot;$number $plural&amp;quot;;&lt;br /&gt;
        } else {&lt;br /&gt;
            return &amp;quot;$number {$singular}s&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    // Other helper functions.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Problems==&lt;br /&gt;
&lt;br /&gt;
I think this gives us the fastest possible runtime performance (particularly when combined with a PHP accelerator. Of course, it leaves open the following problems:&lt;br /&gt;
* what string format do translators to edit? (I suggest we copy the maketext format.)&lt;br /&gt;
* can we write the &amp;lt;tt&amp;gt;compile_lang_strings&amp;lt;/tt&amp;gt; function?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Development:Languages]]&lt;br /&gt;
&lt;br /&gt;
{{CategoryDeveloper}}&lt;br /&gt;
[[Category:Language]]&lt;/div&gt;</summary>
		<author><name>1&gt;Mina</name></author>
	</entry>
</feed>