1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Use of this source code is governed by a BSD-style license that can be 306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// found in the LICENSE file. 406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "chrome/common/time_format.h" 606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <vector> 806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h" 1006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/logging.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 1206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/stl_util-inl.h" 133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string16.h" 1406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/time.h" 1506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/utf_string_conversions.h" 1606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "grit/generated_resources.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 1806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/datefmt.h" 1906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/locid.h" 2006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/plurfmt.h" 2106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/plurrule.h" 2206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/smpdtfmt.h" 2306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 2406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochusing base::Time; 2506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochusing base::TimeDelta; 2606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 2706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochnamespace { 2806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 2906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const char kFallbackFormatSuffixShort[] = "}"; 3006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const char kFallbackFormatSuffixLeft[] = " left}"; 3106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const char kFallbackFormatSuffixAgo[] = " ago}"; 3206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 3306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Contains message IDs for various time units and pluralities. 3406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstruct MessageIDs { 3506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // There are 4 different time units and 6 different pluralities. 3606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch int ids[4][6]; 3706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}; 3806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 3906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Message IDs for different time formats. 4006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const MessageIDs kTimeShortMessageIDs = { { 4106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 4206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_SECS_DEFAULT, IDS_TIME_SEC_SINGULAR, IDS_TIME_SECS_ZERO, 4306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_SECS_TWO, IDS_TIME_SECS_FEW, IDS_TIME_SECS_MANY 4406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }, 4506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 4606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_MINS_DEFAULT, IDS_TIME_MIN_SINGULAR, IDS_TIME_MINS_ZERO, 4706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_MINS_TWO, IDS_TIME_MINS_FEW, IDS_TIME_MINS_MANY 4806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }, 4906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 5006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_HOURS_DEFAULT, IDS_TIME_HOUR_SINGULAR, IDS_TIME_HOURS_ZERO, 5106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_HOURS_TWO, IDS_TIME_HOURS_FEW, IDS_TIME_HOURS_MANY 5206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }, 5306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 5406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_DAYS_DEFAULT, IDS_TIME_DAY_SINGULAR, IDS_TIME_DAYS_ZERO, 5506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_DAYS_TWO, IDS_TIME_DAYS_FEW, IDS_TIME_DAYS_MANY 5606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 5706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} }; 5806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 5906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const MessageIDs kTimeRemainingMessageIDs = { { 6006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 6106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_SECS_DEFAULT, IDS_TIME_REMAINING_SEC_SINGULAR, 6206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_SECS_ZERO, IDS_TIME_REMAINING_SECS_TWO, 6306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_SECS_FEW, IDS_TIME_REMAINING_SECS_MANY 6406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }, 6506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 6606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_MINS_DEFAULT, IDS_TIME_REMAINING_MIN_SINGULAR, 6706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_MINS_ZERO, IDS_TIME_REMAINING_MINS_TWO, 6806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_MINS_FEW, IDS_TIME_REMAINING_MINS_MANY 6906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }, 7006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 7106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_HOURS_DEFAULT, IDS_TIME_REMAINING_HOUR_SINGULAR, 7206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_HOURS_ZERO, IDS_TIME_REMAINING_HOURS_TWO, 7306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_HOURS_FEW, IDS_TIME_REMAINING_HOURS_MANY 7406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }, 7506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 7606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_DAYS_DEFAULT, IDS_TIME_REMAINING_DAY_SINGULAR, 7706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_DAYS_ZERO, IDS_TIME_REMAINING_DAYS_TWO, 7806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_REMAINING_DAYS_FEW, IDS_TIME_REMAINING_DAYS_MANY 7906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 8006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} }; 8106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 8206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const MessageIDs kTimeElapsedMessageIDs = { { 8306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 8406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_SECS_DEFAULT, IDS_TIME_ELAPSED_SEC_SINGULAR, 8506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_SECS_ZERO, IDS_TIME_ELAPSED_SECS_TWO, 8606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_SECS_FEW, IDS_TIME_ELAPSED_SECS_MANY 8706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }, 8806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 8906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_MINS_DEFAULT, IDS_TIME_ELAPSED_MIN_SINGULAR, 9006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_MINS_ZERO, IDS_TIME_ELAPSED_MINS_TWO, 9106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_MINS_FEW, IDS_TIME_ELAPSED_MINS_MANY 9206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }, 9306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 9406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_HOURS_DEFAULT, IDS_TIME_ELAPSED_HOUR_SINGULAR, 9506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_HOURS_ZERO, IDS_TIME_ELAPSED_HOURS_TWO, 9606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_HOURS_FEW, IDS_TIME_ELAPSED_HOURS_MANY 9706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }, 9806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { 9906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_DAYS_DEFAULT, IDS_TIME_ELAPSED_DAY_SINGULAR, 10006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_DAYS_ZERO, IDS_TIME_ELAPSED_DAYS_TWO, 10106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch IDS_TIME_ELAPSED_DAYS_FEW, IDS_TIME_ELAPSED_DAYS_MANY 10206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 10306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} }; 10406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 10506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Different format types. 10606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochenum FormatType { 10706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch FORMAT_SHORT, 10806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch FORMAT_REMAINING, 10906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch FORMAT_ELAPSED, 11006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}; 11106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 11206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} // namespace 11306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 11406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass TimeFormatter { 11506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public: 11606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch const std::vector<icu::PluralFormat*>& formatter(FormatType format_type) { 11706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch switch (format_type) { 11806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch case FORMAT_SHORT: 11906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return short_formatter_; 12006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch case FORMAT_REMAINING: 12106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return time_left_formatter_; 12206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch case FORMAT_ELAPSED: 12306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return time_elapsed_formatter_; 12406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch default: 12506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch NOTREACHED(); 12606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return short_formatter_; 12706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 12806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 12906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch private: 13006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch static const MessageIDs& GetMessageIDs(FormatType format_type) { 13106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch switch (format_type) { 13206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch case FORMAT_SHORT: 13306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return kTimeShortMessageIDs; 13406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch case FORMAT_REMAINING: 13506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return kTimeRemainingMessageIDs; 13606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch case FORMAT_ELAPSED: 13706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return kTimeElapsedMessageIDs; 13806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch default: 13906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch NOTREACHED(); 14006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return kTimeShortMessageIDs; 14106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 14206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 14306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 14406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch static const char* GetFallbackFormatSuffix(FormatType format_type) { 14506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch switch (format_type) { 14606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch case FORMAT_SHORT: 14706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return kFallbackFormatSuffixShort; 14806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch case FORMAT_REMAINING: 14906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return kFallbackFormatSuffixLeft; 15006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch case FORMAT_ELAPSED: 15106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return kFallbackFormatSuffixAgo; 15206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch default: 15306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch NOTREACHED(); 15406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return kFallbackFormatSuffixShort; 15506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 15606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 15706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 15806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch TimeFormatter() { 15906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch BuildFormats(FORMAT_SHORT, &short_formatter_); 16006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch BuildFormats(FORMAT_REMAINING, &time_left_formatter_); 16106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch BuildFormats(FORMAT_ELAPSED, &time_elapsed_formatter_); 16206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 16306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch ~TimeFormatter() { 16406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch STLDeleteContainerPointers(short_formatter_.begin(), 16506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch short_formatter_.end()); 16606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch STLDeleteContainerPointers(time_left_formatter_.begin(), 16706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch time_left_formatter_.end()); 16806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch STLDeleteContainerPointers(time_elapsed_formatter_.begin(), 16906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch time_elapsed_formatter_.end()); 17006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 17121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen friend struct base::DefaultLazyInstanceTraits<TimeFormatter>; 17206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 17306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch std::vector<icu::PluralFormat*> short_formatter_; 17406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch std::vector<icu::PluralFormat*> time_left_formatter_; 17506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch std::vector<icu::PluralFormat*> time_elapsed_formatter_; 17606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch static void BuildFormats(FormatType format_type, 17706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch std::vector<icu::PluralFormat*>* time_formats); 17806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch static icu::PluralFormat* createFallbackFormat( 17906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch const icu::PluralRules& rules, int index, FormatType format_type); 18006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 18106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch DISALLOW_COPY_AND_ASSIGN(TimeFormatter); 18206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}; 18306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 18421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<TimeFormatter> g_time_formatter( 18521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen base::LINKER_INITIALIZED); 18621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 18706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid TimeFormatter::BuildFormats( 18806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch FormatType format_type, std::vector<icu::PluralFormat*>* time_formats) { 18906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch static const icu::UnicodeString kKeywords[] = { 19006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch UNICODE_STRING_SIMPLE("other"), UNICODE_STRING_SIMPLE("one"), 19106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch UNICODE_STRING_SIMPLE("zero"), UNICODE_STRING_SIMPLE("two"), 19206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch UNICODE_STRING_SIMPLE("few"), UNICODE_STRING_SIMPLE("many") 19306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }; 19406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch UErrorCode err = U_ZERO_ERROR; 19506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch scoped_ptr<icu::PluralRules> rules( 19606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch icu::PluralRules::forLocale(icu::Locale::getDefault(), err)); 19706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch if (U_FAILURE(err)) { 19806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch err = U_ZERO_ERROR; 19906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch icu::UnicodeString fallback_rules("one: n is 1", -1, US_INV); 20006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch rules.reset(icu::PluralRules::createRules(fallback_rules, err)); 20106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch DCHECK(U_SUCCESS(err)); 20206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 20306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 20406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch const MessageIDs& message_ids = GetMessageIDs(format_type); 20506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 20606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch for (int i = 0; i < 4; ++i) { 20706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch icu::UnicodeString pattern; 20806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch for (size_t j = 0; j < arraysize(kKeywords); ++j) { 20906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch int msg_id = message_ids.ids[i][j]; 2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string sub_pattern = l10n_util::GetStringUTF8(msg_id); 21106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // NA means this keyword is not used in the current locale. 21206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // Even if a translator translated for this keyword, we do not 21306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // use it unless it's 'other' (j=0) or it's defined in the rules 21406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // for the current locale. Special-casing of 'other' will be removed 21506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // once ICU's isKeyword is fixed to return true for isKeyword('other'). 21606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch if (sub_pattern.compare("NA") != 0 && 21706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch (j == 0 || rules->isKeyword(kKeywords[j]))) { 21806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch pattern += kKeywords[j]; 21906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch pattern += UNICODE_STRING_SIMPLE("{"); 22006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch pattern += icu::UnicodeString(sub_pattern.c_str(), "UTF-8"); 22106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch pattern += UNICODE_STRING_SIMPLE("}"); 22206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 22306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 22406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch icu::PluralFormat* format = new icu::PluralFormat(*rules, pattern, err); 22506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch if (U_SUCCESS(err)) { 22606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch time_formats->push_back(format); 22706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } else { 22806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch delete format; 22906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch time_formats->push_back(createFallbackFormat(*rules, i, format_type)); 23006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // Reset it so that next ICU call can proceed. 23106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch err = U_ZERO_ERROR; 23206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 23306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 23406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} 23506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 23606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Create a hard-coded fallback plural format. This will never be called 23706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// unless translators make a mistake. 23806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochicu::PluralFormat* TimeFormatter::createFallbackFormat( 23906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch const icu::PluralRules& rules, int index, FormatType format_type) { 24006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch static const icu::UnicodeString kUnits[4][2] = { 24106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { UNICODE_STRING_SIMPLE("sec"), UNICODE_STRING_SIMPLE("secs") }, 24206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { UNICODE_STRING_SIMPLE("min"), UNICODE_STRING_SIMPLE("mins") }, 24306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { UNICODE_STRING_SIMPLE("hour"), UNICODE_STRING_SIMPLE("hours") }, 24406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch { UNICODE_STRING_SIMPLE("day"), UNICODE_STRING_SIMPLE("days") } 24506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch }; 24606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch icu::UnicodeString suffix(GetFallbackFormatSuffix(format_type), -1, US_INV); 24706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch icu::UnicodeString pattern; 24806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch if (rules.isKeyword(UNICODE_STRING_SIMPLE("one"))) { 24906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch pattern += UNICODE_STRING_SIMPLE("one{# ") + kUnits[index][0] + suffix; 25006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 25106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch pattern += UNICODE_STRING_SIMPLE(" other{# ") + kUnits[index][1] + suffix; 25206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch UErrorCode err = U_ZERO_ERROR; 25306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch icu::PluralFormat* format = new icu::PluralFormat(rules, pattern, err); 25406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch DCHECK(U_SUCCESS(err)); 25506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return format; 25606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} 25706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) { 25906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch if (delta.ToInternalValue() < 0) { 26006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch NOTREACHED() << "Negative duration"; 2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return string16(); 26206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 26306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 26406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch int number; 26506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 26606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch const std::vector<icu::PluralFormat*>& formatters = 26721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen g_time_formatter.Get().formatter(format_type); 26806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 26906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch UErrorCode error = U_ZERO_ERROR; 27006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch icu::UnicodeString time_string; 27106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // Less than a minute gets "X seconds left" 27206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch if (delta.ToInternalValue() < Time::kMicrosecondsPerMinute) { 27306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch number = static_cast<int>(delta.ToInternalValue() / 27406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch Time::kMicrosecondsPerSecond); 27506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch time_string = formatters[0]->format(number, error); 27606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 27706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // Less than 1 hour gets "X minutes left". 27806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } else if (delta.ToInternalValue() < Time::kMicrosecondsPerHour) { 27906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch number = static_cast<int>(delta.ToInternalValue() / 28006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch Time::kMicrosecondsPerMinute); 28106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch time_string = formatters[1]->format(number, error); 28206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 28306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // Less than 1 day remaining gets "X hours left" 28406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } else if (delta.ToInternalValue() < Time::kMicrosecondsPerDay) { 28506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch number = static_cast<int>(delta.ToInternalValue() / 28606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch Time::kMicrosecondsPerHour); 28706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch time_string = formatters[2]->format(number, error); 28806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 28906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // Anything bigger gets "X days left" 29006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } else { 29106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch number = static_cast<int>(delta.ToInternalValue() / 29206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch Time::kMicrosecondsPerDay); 29306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch time_string = formatters[3]->format(number, error); 29406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch } 29506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 29606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // With the fallback added, this should never fail. 29706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch DCHECK(U_SUCCESS(error)); 29806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch int capacity = time_string.length() + 1; 2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick string16 result; 30006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch time_string.extract(static_cast<UChar*>( 3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick WriteInto(&result, capacity)), 30206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch capacity, error); 30306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch DCHECK(U_SUCCESS(error)); 3043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return result; 30506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} 30606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 30706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// static 3083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstring16 TimeFormat::TimeElapsed(const TimeDelta& delta) { 30906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return FormatTimeImpl(delta, FORMAT_ELAPSED); 31006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} 31106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 31206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// static 3133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstring16 TimeFormat::TimeRemaining(const TimeDelta& delta) { 31406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return FormatTimeImpl(delta, FORMAT_REMAINING); 31506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} 31606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 31706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// static 3183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstring16 TimeFormat::TimeRemainingShort(const TimeDelta& delta) { 31906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch return FormatTimeImpl(delta, FORMAT_SHORT); 32006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} 32106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 32206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// static 3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstring16 TimeFormat::RelativeDate( 32406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch const Time& time, 32506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch const Time* optional_midnight_today) { 32606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch Time midnight_today = optional_midnight_today ? *optional_midnight_today : 32706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch Time::Now().LocalMidnight(); 32806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 32906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch // Filter out "today" and "yesterday" 33006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch if (time >= midnight_today) 3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return l10n_util::GetStringUTF16(IDS_PAST_TIME_TODAY); 33206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch else if (time >= midnight_today - 33306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch TimeDelta::FromMicroseconds(Time::kMicrosecondsPerDay)) 3343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return l10n_util::GetStringUTF16(IDS_PAST_TIME_YESTERDAY); 33506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch 3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return string16(); 33706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} 338