diff --git a/README.md b/README.md index 9671e11..03c249f 100644 --- a/README.md +++ b/README.md @@ -445,6 +445,23 @@ Nuggets translations can be modified at runtime as follows: } ``` +#### PO customization + +i18n allows you to change the PO file name to use and use PO files from other sources (when working with multiple projects for example). +To enable this feature, you can set : + + +```xml + + ... + + + ... + +``` + +Note : i18n.LocaleOtherFiles paths are relative to the directory of the file {i18n.LocaleFilename}.po (messages.po by default). + ### URL Localization In keeping with emerging standards for internationalized web applications, i18n provides support for diff --git a/src/i18n.Domain/Concrete/POTranslationRepository.cs b/src/i18n.Domain/Concrete/POTranslationRepository.cs index 609cf0a..85bf6d8 100644 --- a/src/i18n.Domain/Concrete/POTranslationRepository.cs +++ b/src/i18n.Domain/Concrete/POTranslationRepository.cs @@ -142,7 +142,7 @@ public CacheDependency GetCacheDependencyForAllLanguages() /// The translation you wish to save. Must have Language shortag filled out. public void SaveTranslation(Translation translation) { - var templateFilePath = GetAbsoluteLocaleDir() + "/messages.pot"; + var templateFilePath = GetAbsoluteLocaleDir() + "/" + _settings.LocaleFilename + ".pot"; var POTDate = DateTime.Now; if (File.Exists(templateFilePath)) { POTDate = File.GetLastWriteTime(templateFilePath); } @@ -258,7 +258,7 @@ public void SaveTranslation(Translation translation) /// A list of template items to save. The list should be all template items for the entire project. public void SaveTemplate(IDictionary items) { - string filePath = GetAbsoluteLocaleDir() + "/messages.pot"; + string filePath = GetAbsoluteLocaleDir() + "/" + _settings.LocaleFilename + ".pot"; string backupPath = filePath + ".backup"; if (File.Exists(filePath)) //we backup one version. more advanced backup solutions could be added here. @@ -350,9 +350,11 @@ private string GetAbsoluteLocaleDir() return _settings.LocaleDirectory; } - private string GetPathForLanguage(string langtag) + private string GetPathForLanguage(string langtag, string filename = null) { - return Path.Combine(GetAbsoluteLocaleDir(), langtag, "messages.po"); + if (!filename.IsSet()) + filename = _settings.LocaleFilename; + return Path.Combine(GetAbsoluteLocaleDir(), langtag, filename + ".po"); } /// @@ -370,83 +372,97 @@ private Translation ParseTranslationFile(string langtag) translation.LanguageInformation = language; var items = new ConcurrentDictionary(); - string path = GetPathForLanguage(langtag); - - if (File.Exists(path)) { - DebugHelpers.WriteLine("Reading file: {0}", path); - - using (var fs = File.OpenText(path)) - { - // http://www.gnu.org/s/hello/manual/gettext/PO-Files.html - - string line; - bool itemStarted = false; - while ((line = fs.ReadLine()) != null) - { - var extractedComments = new List(); - var translatorComments = new List(); - var flags = new List(); - var references = new List(); - - //read all comments, flags and other descriptive items for this string - //if we have #~ its a historical/log entry but it is the messageID/message so we skip this do/while - if (line.StartsWith("#") && !line.StartsWith("#~")) - { - do - { - itemStarted = true; - switch (line[1]) - { - case '.': //Extracted comments - extractedComments.Add(line.Substring(2).Trim()); - break; - case ':': //references - references.Add(ReferenceContext.Parse(line.Substring(2).Trim())); - break; - case ',': //flags - flags.Add(line.Substring(2).Trim()); - break; - case '|': //msgid previous-untranslated-string - NOT used by us - break; - default: //translator comments - translatorComments.Add(line.Substring(1).Trim()); - break; - } - - } while ((line = fs.ReadLine()) != null && line.StartsWith("#")); - } - - if (line != null && (itemStarted || line.StartsWith("#~"))) - { - TranslationItem item = ParseBody(fs, line, extractedComments); - if (item != null) { - // - item.TranslatorComments = translatorComments; - item.ExtractedComments = extractedComments; - item.Flags = flags; - item.References = references; - // - items.AddOrUpdate( - item.MsgKey, - // Add routine. - k => { - return item; - }, - // Update routine. - (k, v) => { - v.References = v.References.Append(item.References); - var referencesAsComments = item.References.Select(r => r.ToComment()).ToList(); - v.ExtractedComments = v.ExtractedComments.Append(referencesAsComments); - v.TranslatorComments = v.TranslatorComments.Append(referencesAsComments); - v.Flags = v.Flags.Append(referencesAsComments); - return v; - }); + List paths = new List(); + + paths.Add(GetPathForLanguage(langtag)); + + foreach (var file in _settings.LocaleOtherFiles) + { + paths.Add(GetPathForLanguage(langtag, file)); + } + + foreach (var path in paths) + { + if (File.Exists(path)) + { + DebugHelpers.WriteLine("Reading file: {0}", path); + + using (var fs = File.OpenText(path)) + { + // http://www.gnu.org/s/hello/manual/gettext/PO-Files.html + + string line; + bool itemStarted = false; + while ((line = fs.ReadLine()) != null) + { + var extractedComments = new List(); + var translatorComments = new List(); + var flags = new List(); + var references = new List(); + + //read all comments, flags and other descriptive items for this string + //if we have #~ its a historical/log entry but it is the messageID/message so we skip this do/while + if (line.StartsWith("#") && !line.StartsWith("#~")) + { + do + { + itemStarted = true; + switch (line[1]) + { + case '.': //Extracted comments + extractedComments.Add(line.Substring(2).Trim()); + break; + case ':': //references + references.Add(ReferenceContext.Parse(line.Substring(2).Trim())); + break; + case ',': //flags + flags.Add(line.Substring(2).Trim()); + break; + case '|': //msgid previous-untranslated-string - NOT used by us + break; + default: //translator comments + translatorComments.Add(line.Substring(1).Trim()); + break; + } + + } while ((line = fs.ReadLine()) != null && line.StartsWith("#")); + } + + if (line != null && (itemStarted || line.StartsWith("#~"))) + { + TranslationItem item = ParseBody(fs, line, extractedComments); + if (item != null) + { + // + item.TranslatorComments = translatorComments; + item.ExtractedComments = extractedComments; + item.Flags = flags; + item.References = references; + // + items.AddOrUpdate( + item.MsgKey, + // Add routine. + k => { + return item; + }, + // Update routine. + (k, v) => + { + v.References = v.References.Append(item.References); + var referencesAsComments = + item.References.Select(r => r.ToComment()).ToList(); + v.ExtractedComments = v.ExtractedComments.Append(referencesAsComments); + v.TranslatorComments = v.TranslatorComments.Append(referencesAsComments); + v.Flags = v.Flags.Append(referencesAsComments); + return v; + }); + } } - } - itemStarted = false; - } - } + itemStarted = false; + } + } + } } translation.Items = items; return translation; diff --git a/src/i18n.Domain/Concrete/i18nSettings.cs b/src/i18n.Domain/Concrete/i18nSettings.cs index d4014e2..6bb6297 100644 --- a/src/i18n.Domain/Concrete/i18nSettings.cs +++ b/src/i18n.Domain/Concrete/i18nSettings.cs @@ -72,6 +72,51 @@ public virtual string LocaleDirectory #endregion + #region Locale filename + + private const string _localeFilenameDefault = "messages"; + public virtual string LocaleFilename + { + get + { + string prefixedString = GetPrefixedString("LocaleFilename"); + string setting = _settingService.GetSetting(prefixedString); + if (setting.IsSet()) + { + return setting; + } + + return _localeFilenameDefault; + } + set + { + string prefixedString = GetPrefixedString("LocaleFilename"); + _settingService.SetSetting(prefixedString, value); + } + } + + private const string _localeOtherFilesDefault = ""; + public virtual IEnumerable LocaleOtherFiles + { + get + { + string prefixedString = GetPrefixedString("LocaleOtherFiles"); + string setting = _settingService.GetSetting(prefixedString); + if (!setting.IsSet()) + { + setting = _localeOtherFilesDefault; + } + + return setting.Split(';'); + } + set + { + string prefixedString = GetPrefixedString("LocaleOtherFiles"); + _settingService.SetSetting(prefixedString, string.Join(";", value)); + } + } + + #endregion #region White list