【问题标题】:How to make localization on months / days for D3js?如何为 D3js 进行几个月/几天的本地化?
【发布时间】:2013-10-09 14:10:38
【问题描述】:

我正在寻找一种在 D3 上进行本地化的方法

我找到了值

d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ],
d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], 
d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], 
d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];

D3 内部,但由于它们是 D3 的本地/私有,我(显然)无法访问它们。

任何提示都会很棒,谢谢:)


更新 1:

似乎只有重新编译才能发挥作用 - 但不能被购买 - 所以最终在缩小版本中对编辑进行硬编码 - 真丢人...


更新 2:

将尝试研究如何让 D3 接受像 fx moment.js 这样的“即时”本地化设置:

moment.lang('da', {
    months : "Januar_Februar_Marts_April_Maj_Juni_Juli_August_September_Oktober_November_December".split("_"),
    monthsShort : "Jan_Feb_Mar_Apr_Maj_Jun_Jul_Aug_Sep_Okt_Nov_Dec".split("_"),
    weekdays : "Søndag_Mandag_Tirsdag_Onsdag_Torsdag_Fredag_Lørdag".split("_"),
    weekdaysShort : "Søn_Man_Tir_Ons_Tor_Fre_Lør".split("_"),
    weekdaysMin : "Sø_Ma_Ti_On_To_Fr_Lø".split("_"),
    ordinal : '%d.',
    week : {
        dow : 1, // Monday is the first day of the week.
        doy : 4  // The week that contains Jan 4th is the first week of the year.
    }
});

【问题讨论】:

  • 您希望以何种方式进行本地化?如果你有日期对象,那么调用 .getDay() 会给你一个整数值,星期日为 0。

标签: d3.js


【解决方案1】:

我刚刚遇到了同样的问题,我找到了无需重新编译 d3 即可修复它的方法。

https://github.com/mbostock/d3/wiki/Localization

文档中提到了函数 d3.locale,这个函数构建了用于格式化数字和日期的函数。因此,如果您使用自己的本地化规则调用它,您就成功了一半。

var myFormatters = d3.locale({
  "decimal": ".",
  "thousands": ",",
  "grouping": [3],
  "currency": ["$", ""],
  "dateTime": "%a %b %e %X %Y",
  "date": "%m/%d/%Y",
  "time": "%H:%M:%S",
  "periods": ["AM", "PM"],
  "days": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
  "shortDays": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
  "months": ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"],
  "shortMonths": ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"]
});

下一步是实际告诉 d3 使用这个新的格式化函数。因此,要使用新的时间格式化程序,请执行以下操作:

d3.time.format = myFormatters.timeFormat;

【讨论】:

  • 要格式化数字,请使用d3.format = myFormatters.numberFormat;
  • 这不适用于时间轴刻度,因为d3.time.scale 使用了一些内部符号,我看不到从外部重新创建它的方法。覆盖d3.time.format 似乎效果不佳,因为时间格式是使用内部d3_time_format 进行的。这就是 3.4.11 版本。
  • 除了一般糟糕的 i18n 设计之外,可以通过修补来解决,d3.time.format.multi 本身就是一个挑战,因为它不映射到 CLDR 格式。例如。即使一个月份名称已本地化,订单或月份和日期也可能不同,并且本身受 l10n 的影响。
【解决方案2】:

只是想我会添加到@Adrian Salazar 的答案,因为我花了一段时间才把它弄好。 如果您正在使用“开箱即用”的 d3 时间刻度制作轴。您可以使用 timeFormat.multi 将其设置为语言环境

var localeFormatter = d3.locale({
    "decimal": ",",
    "thousands": ".",
    "grouping": [3],
    "currency": ["€", ""],
    "dateTime": "%a %b %e %X %Y",
    "date": "%d-%m-%Y",
    "time": "%H:%M:%S",
    "periods": ["AM", "PM"],
    "days": ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"],
    "shortDays": ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za"],
    "months": ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"],
    "shortMonths": ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"]
})

var tickFormat = localeFormatter.timeFormat.multi([
    ["%H:%M", function(d) { return d.getMinutes(); }],
    ["%H:%M", function(d) { return d.getHours(); }],
    ["%a %d", function(d) { return d.getDay() && d.getDate() != 1; }],
    ["%b %d", function(d) { return d.getDate() != 1; }],
    ["%B", function(d) { return d.getMonth(); }],
    ["%Y", function() { return true; }]
]);

axis.tickFormat(tickFormat);

【讨论】:

    【解决方案3】:

    您可以创建自定义 d3 时间格式化程序并使用 moment.js 进行本地化。例如,要创建具有本地化日期的轴:

    var x = d3.time.scale();
    
    var myTimeFormatter = function(date) {
        return moment(date).format("LL");
    };
    
    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .tickFormat(myTimeFormatter);
    

    然后使用moment.lang 添加对其他语言的支持并切换当前语言。具体请参考http://momentjs.com/docs/#/i18n

    【讨论】:

    • 像魅力一样工作。谢谢
    【解决方案4】:

    来自documentation

    D3 的实现在编译时根据 $LOCALE 环境变量固定到一个语言环境。

    为了将其本地化到您的环境,您需要在具有所需区域设置的机器上重新编译 d3.js(和 d3.min.js)。这将替换您在源代码中看到的字符串。

    【讨论】:

      【解决方案5】:

      对于 D3 >= 4,我使用它来将 de_DE 设置为默认语言环境:

      import { formatDefaultLocale } from 'd3-format';
      import { timeFormat, timeFormatDefaultLocale } from 'd3-time-format';
      import {
          timeSecond,
          timeMinute,
          timeHour,
          timeDay,
          timeMonth,
          timeWeek,
          timeYear,
      } from 'd3-time';
      
      // set default locale
      formatDefaultLocale({
          "decimal": ",",
          "thousands": ".",
          "grouping": [3],
          "currency": ["", "\u00a0€"]
      });
      
      // set default time locale
      timeFormatDefaultLocale({
          "dateTime": "%A, der %e. %B %Y, %X",
          "date": "%d.%m.%Y",
          "time": "%H:%M:%S",
          "periods": ["AM", "PM"],
          "days": ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
          "shortDays": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
          "months": ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
          "shortMonths": ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"]
      });
      
      let formatMillisecond = timeFormat(".%L");
      let formatSecond = timeFormat(":%S");
      let formatMinute = timeFormat("%I:%M");
      let formatHour = timeFormat("%I %p");
      let formatDay = timeFormat("%a %d");
      let formatWeek = timeFormat("%b %d");
      let formatMonth = timeFormat("%B");
      let formatYear = timeFormat("%Y");
      
      function tickFormat (date) {
          function multiFormat (date) {
              return (timeSecond(date) < date ? formatMillisecond
                  : timeMinute(date) < date ? formatSecond
                  : timeHour(date) < date ? formatMinute
                  : timeDay(date) < date ? formatHour
                  : timeMonth(date) < date ? (timeWeek(date) < date ? formatDay : formatWeek)
                  : timeYear(date) < date ? formatMonth
                  : formatYear)(date);
          }
          return multiFormat(date);
      }
      
      axis.tickFormat(tickFormat);
      

      【讨论】:

        【解决方案6】:

        多个文件: 重新编译 Lib 并提供 10.000 行代码的多个文件,仅 5 行不同...这是最佳实践吗?

        即时更改补丁: 由于 locale-string 是私有的,您可以(或者更确切地说需要)修补 D3.js。 不幸的是,任何修补的库都会使更新过程复杂化。 internationalization and localization at runtime

        显示了一个即时本地化的示例

        官方提交: Mike Bostock 反应迅速,他有一个commit on locale-branch。这似乎是初稿,但也许对你有帮助。

        问题

        【讨论】:

          【解决方案7】:

          我这样做了,它成功了

          var monthss = ['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'];
          var x = d3.time.scale()
              .range([0, width]);
          var xAxis = d3.svg.axis()
              .scale(x)
              .orient("bottom")
              .ticks(d3.time.months)
              .tickFormat(function(d,i) { 
                if(i<monthss.length){
                  return monthss[i];
                }
                return monthss[i-monthss.length]
               });
          

          如果是因为我画了两年。希望这会有所帮助。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-06-01
            • 1970-01-01
            • 2021-06-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-04-21
            相关资源
            最近更新 更多