Search code examples
phpcoldfusioninternationalization

PHP i18n language file to ColdFusion struct converter


The Task

My task was to take a php i18n language file and convert it to a ColdFusion struct. Here is a portion of the input

...
"ASK_DELETE"                =>  "<em>D</em>elete", // 'd' is the accesskey identifier
"BACKUP_OF"                 =>  'Backup of',
"PAGE_TITLE"                =>  "Page Title",
...

Current Attempt at converting

The code below does work for the php language file that I have been handed. The issue is, the code looks like the beginning of spaghetti code. Some of the things I don't like are

  • If one more string pattern comes along, things will crash
  • I have a variable called "value"
  • Lots of mid string based chopping.

The code looks like the beginning of spaghetti code. What kinds of things should be done about this?

    <cffunction name="readPropertiesFile" returnType="Struct" hint="Read a properties file and return a structure">
    <cfargument name="propertiesFile" type="string" required="true" hint="path to properties file">


    <cfscript>
        VAR stProperties = {};
        VAR phpText = "";
        VAR key = "";
        VAR value = "";
        VAR line = "";

       var propertiesFilePath = "#GetDirectoryFromPath(GetBaseTemplatePath())##arguments.propertiesfile#";


       if (NOT FileExists(propertiesFilePath))

        return stProperties;

     </cfscript>




    <!--- read props file --->
    <cffile action="read" file="#propertiesFilePath#" variable="phpText">



    <!--- remove any whitespace at top and tail --->
    <cfset phpText = trim(phpText)>

    <!--- remove comments and blank lines --->
    <cfset phpText = ReReplace(phpText,"(?m)\##.*?$", "","all")>
    <cfset phpText = ReReplace(phpText,"[#Chr(10)#]{2,}", "#Chr(10)#","all")>
    <cfset phpText = ReplaceList(phpText, '",', '"')>


    <!--- loop over each line, ignore comments (#...) and insert keys/values into return struct --->
    <cfloop list="#phpText#" index="line" delimiters="#CHR(10)#">
    <cfscript>

    line = trim(line);
    splitAt = Find("=>", line);
    CommentAt = Find("//", line);

    if (splitAt != 0)   {

        key =  replacelist(trim(Left(line, splitAt - 1)), '"', "");

        if (CommentAt == 0)
    value = replacelist(trim(Mid(line, splitAt + 2, 1000)), '"', '');
        else
            value = replacelist(trim(Mid(line, splitAt + 2, CommentAt - (splitAt + 2))), '"', '');

        //  Remove trailing , 
    if (right(value, 1) == ",")
            value = mid(value, 1, len(value) - 1);


    if (right(value, 1) == "'")
        value = mid(value, 1, len(value) - 1);


    if (left(value, 1) == "'")
        value = mid(value, 2, 1000);



        stProperties[key] = value;
        } // end if
    </cfscript>
</cfloop>

<cfreturn stProperties>


Solution

  • This would be my approach. You can of course make this more resilient or add error trapping to catch inconsistent file parsing. I'm assuming there won't be quotes in the key values.

    <!--- Going on the Assumption there isn't commas or quotations inside the values of the key --->
    <cfsavecontent variable="fileData">
    
    "ASK_DELETE"                =>  "<em>D</em>elete", // 'd' is the accesskey identifier
    "BACKUP_OF"                 =>  'Backup of',
    
    "PAGE_TITLE"                =>  "Page Title"
    
    </cfsavecontent>
    
    <cfset i18n = structNew()>
    <!--- Remove // Comments --->
    <cfset fileData = REReplace(fileData,"//.*?\n","","ALL")>
    <!--- Simplify Delimiter --->
    <cfset fileData = Replace(fileData,"=>","|","ALL")>
    
    <cfloop list="#fileData#" delimiters="," index="thisEntry">
        <!--- Strip Quotes and Pull Entries --->
        <cfset key = REReplace(ListFirst(thisEntry,"|"),"[""']","","ALL")>
        <cfset value = REReplace(ListLast(thisEntry,"|"),"[""']","","ALL")>
        <cfset structInsert(i18n,trim(key),trim(value))>
    </cfloop>
    
    <cfdump var="#i18n#">