let output_po chn po =
  let comment_max_length = 
    80
  in
  let fpf x = 
    Printf.fprintf chn x
  in
  let escape_string str =
    let rec escape_string_aux buff i =
      if i < String.length str then
        let () =
          match String.get str i with 
            | '\n'   -> Buffer.add_string buff "\\n"
            | '\t'   -> Buffer.add_string buff "\\t" 
            | '\b'   -> Buffer.add_string buff "\\b" 
            | '\r'   -> Buffer.add_string buff "\\r" 
            | '\012' -> Buffer.add_string buff "\\f" 
            | '\011' -> Buffer.add_string buff "\\v" 
            | '\007' -> Buffer.add_string buff "\\a" 
            | '"'    -> Buffer.add_string buff "\\\""
            | '\\'   -> Buffer.add_string buff "\\\\"
            | e ->
                Buffer.add_char buff e
        in
          escape_string_aux buff (i+1)
      else
        (
        )
    in
    let buff = 
      Buffer.create ((String.length str) + 2)
    in
      Buffer.add_char buff '"';
      escape_string_aux buff 0;
      Buffer.add_char buff '"';
      Buffer.contents buff
  in

  let hyphens chn lst = 
    match lst with
      [] ->
        ()
    | lst ->
        Printf.fprintf chn 
          "%s" 
          (String.concat "\n" (List.map escape_string lst))
  in

  let comment_line str_hyphen str_sep line_max_length token_lst =
    let str_len =
      (List.fold_left (fun acc str -> acc + (String.length str)) 0 token_lst)
      +
      ((List.length token_lst) * (String.length str_sep))
    in
    let buff =
      Buffer.create 
        (str_len + (String.length str_hyphen) * (str_len / line_max_length))
    in
    let rec comment_line_aux first_token line_length lst =
      match lst with 
        | str :: tl ->
            let sep_length =
              if first_token then
                0
              else if  (String.length str) + line_length > line_max_length then
                (
                  Buffer.add_char buff '\n';
                  Buffer.add_string buff str_hyphen;
                  Buffer.add_string buff str_sep;
                  (String.length str_hyphen) + (String.length str_sep)
                )
              else
                (
                  Buffer.add_string buff str_sep;
                  String.length str_sep
                )
            in
            Buffer.add_string buff str;
            comment_line_aux false (sep_length + (String.length str) + line_length)  tl
        | [] ->
            Buffer.contents buff
    in
      comment_line_aux true 0 token_lst
  in


  let rec output_po_translation_aux _ commented_translation = 
    (
      match commented_translation.po_comment_filepos with
        |  [] -> 
            ()
        | lst ->
            fpf "%s\n"
              (comment_line
                 "#."
                 " "
                 comment_max_length
                 ("#:" :: (List.map (fun (str,line) -> Printf.sprintf "%s:%d" str line) lst)))
    );
    (
      match commented_translation.po_comment_special with
        | [] ->
            ()
        | lst ->
            fpf "%s\n"
              (comment_line
                 "#."
                 " "
                 comment_max_length
                 ("#," :: lst))
    );
    (
      match commented_translation.po_comment_translation with
        PoSingular(id,str) ->
          (
            fpf "msgid %a\n" hyphens id;
            fpf "msgstr %a\n" hyphens str
          )
      | PoPlural(id,id_plural,lst) ->
          (
            fpf "msgid %a\n" hyphens id;
            fpf "msgid_plural %a\n" hyphens id_plural;
            let _ = List.fold_left 
              ( fun i s -> 
                fpf "msgstr[%i] %a\n" i hyphens s; 
                i + 1
              ) 0 lst
            in
            ()
          )
    );
    fpf "\n"
  in
  MapString.iter output_po_translation_aux po.no_domain;
  MapTextdomain.iter ( 
    fun domain map ->
        fpf "domain %S\n\n" domain;
        MapString.iter output_po_translation_aux map
  ) po.domain